Passed
Push — 16.1 ( ed9096...a3973f )
by Hadi
14:50
created

AppJS.extend.mail_reloadNode   D

Complexity

Conditions 14
Paths 111

Size

Total Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 14
c 1
b 0
f 0
nc 111
nop 1
dl 0
loc 27
rs 4.9146

How to fix   Complexity   

Complexity

Complex classes like AppJS.extend.mail_reloadNode often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/* global msg */
2
3
/**
4
 * mail - static javaScript functions
5
 *
6
 * @link http://www.egroupware.org
7
 * @author EGroupware GmbH [[email protected]]
8
 * @copyright (c) 2013-2014 by EGroupware GmbH <info-AT-egroupware.org>
9
 * @package mail
10
 * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
11
 * @version $Id$
12
 */
13
14
/*egw:uses
15
	/api/js/jquery/jquery.base64.js;
16
*/
17
18
/**
19
 * UI for mail
20
 *
21
 * @augments AppJS
22
 */
23
app.classes.mail = AppJS.extend(
24
{
25
	appname: 'mail',
26
27
	/**
28
	 * et2 widget container
29
	 */
30
	et2: null,
31
	doStatus: null,
32
33
	mail_queuedFolders: [],
34
	mail_queuedFoldersIndex: 0,
35
36
	mail_selectedMails: [],
37
	mail_currentlyFocussed: '',
38
	mail_previewAreaActive: true, // we start with the area active
39
40
	nm_index: 'nm', // nm name of index
41
	mail_fileSelectorWindow: null,
42
	mail_isMainWindow: true,
43
44
	// Some state variables to track preview pre-loading
45
	preview_preload: {
46
		timeout: null,
47
		request: null
48
	},
49
	/**
50
	 *
51
	 */
52
	subscription_treeLastState : "",
53
54
	/**
55
	 * abbrevations for common access rights
56
	 * @array
57
	 *
58
	 */
59
	aclCommonRights:['lrs','lprs','ilprs',	'ilprsw', 'aeiklprstwx', 'custom'],
60
	/**
61
	 * Demonstrates ACL rights
62
	 * @array
63
	 *
64
	 */
65
	aclRights:['l','r','s','w','i','p','c','d','a'],
66
67
	/**
68
	 * In order to store Intervals assigned to window
69
	 * @array of setted intervals
70
	 */
71
	W_INTERVALS:[],
72
73
	/**
74
	 * Initialize javascript for this application
75
	 *
76
	 * @memberOf mail
77
	 */
78
	init: function() {
79
		this._super.apply(this,arguments);
80
		if (!this.egw.is_popup())
81
			// Turn on client side, persistent cache
82
			// egw.data system runs encapsulated below etemplate, so this must be
83
			// done before the nextmatch is created.
84
			this.egw.dataCacheRegister('mail',
85
				// Called to determine cache key
86
				this.nm_cache,
87
				// Called whenever cache is used
88
				// TODO: Change this as needed
89
				function(server_query)
90
				{
91
					// Unlock tree if using a cache, since the server won't
92
					if(!server_query) this.unlock_tree();
93
				},
94
				this
95
			);
96
	},
97
98
	/**
99
	 * Destructor
100
	 */
101
	destroy: function()
102
	{
103
		// Unbind from nm refresh
104
		if(this.et2 != null)
105
		{
106
			var nm = this.et2.getWidgetById(this.nm_index);
107
			if(nm != null)
108
			{
109
				jQuery(nm).off('refresh');
110
			}
111
		}
112
113
		// Unregister client side cache
114
		this.egw.dataCacheUnregister('mail');
115
116
		delete this.et2_obj;
117
		// call parent
118
		this._super.apply(this, arguments);
119
	},
120
121
	/**
122
	 * check and try to reinitialize et2 of module
123
	 */
124
	checkET2: function()
125
	{
126
		//this.et2 should do the same as etemplate2.getByApplication('mail')[0].widgetContainer
127
		if (!this.et2) // if not defined try this in order to recover
128
		{
129
			try
130
			{
131
				this.et2 = etemplate2.getByApplication('mail')[0].widgetContainer;
132
			}
133
			catch(e)
134
			{
135
				return false;
136
			}
137
		}
138
		return true;
139
	},
140
141
	/**
142
	 * This function is called when the etemplate2 object is loaded
143
	 * and ready.  If you must store a reference to the et2 object,
144
	 * make sure to clean it up in destroy().
145
	 *
146
	 * @param et2 etemplate2 Newly ready object
147
	 * @param {string} _name template name
148
	 */
149
	et2_ready: function(et2, _name)
150
	{
151
		// call parent; somehow this function is called more often. (twice on a display and compose) why?
152
		this._super.apply(this, arguments);
153
		this.et2_obj = et2;
154
155
		switch (_name)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
156
		{
157
			case 'mail.sieve.vacation':
158
				this.vacationFilterStatusChange();
159
				break;
160
			case 'mail.index':
161
				var self = this;
162
				jQuery('iframe#mail-index_messageIFRAME').on('load', function()
163
				{
164
					// decrypt preview body if mailvelope is available
165
					self.mailvelopeAvailable(self.mailvelopeDisplay);
166
					self.mail_prepare_print();
167
				});
168
				var nm = this.et2.getWidgetById(this.nm_index);
169
				this.mail_isMainWindow = true;
170
				this.mail_disablePreviewArea(this.egw.preference('previewPane', 'mail') !== 'fixed');
171
				//Get initial folder status
172
				this.mail_refreshFolderStatus(undefined,undefined,false);
173
174
				// Bind to nextmatch refresh to update folder status
175
				if(nm != null && (typeof jQuery._data(nm).events=='undefined'||typeof jQuery._data(nm).events.refresh == 'undefined'))
176
				{
177
					var self = this;
178
					jQuery(nm).on('refresh',function() {self.mail_refreshFolderStatus.call(self,undefined,undefined,false);});
179
				}
180
				var tree_wdg = this.et2.getWidgetById(this.nm_index+'[foldertree]');
181
				if (tree_wdg)
182
				{
183
					tree_wdg.set_onopenstart(jQuery.proxy(this.openstart_tree, this));
184
					tree_wdg.set_onopenend(jQuery.proxy(this.openend_tree, this));
185
				}
186
				// Show vacation notice on load for the current profile (if not called by mail_searchtype_change())
187
				var alreadyrefreshed = this.mail_searchtype_change();
188
				if (!alreadyrefreshed) this.mail_callRefreshVacationNotice();
189
				break;
190
			case 'mail.display':
191
				var self = this;
192
				// Prepare display dialog for printing
193
				// copies iframe content to a DIV, as iframe causes
194
				// trouble for multipage printing
195
196
				jQuery('iframe#mail-display_mailDisplayBodySrc').on('load', function(e)
197
				{
198
					// encrypt body if mailvelope is available
199
					self.mailvelopeAvailable(self.mailvelopeDisplay);
200
					self.mail_prepare_print();
201
202
					// Trigger print command if the mail oppend for printing porpuse
203
					// load event fires twice in IE and the first time the content is not ready
204
					// Check if the iframe content is loaded then trigger the print command
205
					if (window.location.search.search('&print=') >= 0 && jQuery(this.contentWindow.document.body).children().length >0 )
206
					{
207
						self.mail_print();
208
					}
209
				});
210
211
				this.mail_isMainWindow = false;
212
				this.mail_display();
213
214
				// Register attachments for drag
215
				this.register_for_drag(
216
					this.et2.getArrayMgr("content").getEntry('mail_id'),
217
					this.et2.getArrayMgr("content").getEntry('mail_displayattachments')
218
				);
219
				break;
220
			case 'mail.compose':
221
				if (this.et2.getWidgetById('composeToolbar')._actionManager.getActionById('pgp') &&
222
					this.et2.getWidgetById('composeToolbar')._actionManager.getActionById('pgp').checked ||
223
					this.et2.getArrayMgr('content').data.mail_plaintext &&
224
						this.et2.getArrayMgr('content').data.mail_plaintext.indexOf(this.begin_pgp_message) != -1)
225
				{
226
					this.mailvelopeAvailable(this.mailvelopeCompose);
227
				}
228
				var that = this;
229
				var textAreaWidget = this.et2.getWidgetById('mail_htmltext');
230
				this.mail_isMainWindow = false;
231
				this.compose_fieldExpander_init();
232
				this.check_sharing_filemode();
233
234
				this.subject2title();
235
236
				// Set autosaving interval to 2 minutes for compose message
237
				this.W_INTERVALS.push(window.setInterval(function (){
238
					that.saveAsDraft(null, 'autosaving');
239
				}, 120000));
240
241
				/* Control focus actions on subject to handle expanders properly.*/
242
				jQuery("#mail-compose_subject").on({
243
					focus:function(){
244
						that.compose_fieldExpander_init();
245
						that.compose_fieldExpander();
246
					}
247
				});
248
				/*Trigger compose_resizeHandler after the CKEditor is fully loaded*/
249
				jQuery('#mail-compose').on ('load',function() {
250
					if (textAreaWidget && textAreaWidget.ckeditor)
251
					{
252
						textAreaWidget.ckeditor.on('instanceReady', function(){
253
							that.compose_fieldExpander();
254
							if (egwIsMobile()) jQuery(jQuery('iframe.cke_wysiwyg_frame')[0].contentWindow.document.body).css({margin:'0'})
255
						});
256
					}
257
					else
258
					{
259
						that.compose_fieldExpander();
260
					}
261
				});
262
263
				//Resize compose after window resize to not getting scrollbar
264
				jQuery(window).on ('resize',function(e) {
265
					// Stop immediately the resize event if we are in mobile template
266
					if (egwIsMobile())
267
					{
268
						e.stopImmediatePropagation();
269
						return false;
270
					}
271
					that.compose_resizeHandler();
272
				});
273
274
				//Call drag_n_drop initialization for emails on compose
275
				this.init_dndCompose();
276
277
				// Set focus on To/body field
278
				// depending on To field value
279
				var to = this.et2.getWidgetById('to');
280
				if (to && to.get_value() && to.get_value() != '')
281
				{
282
					var content = this.et2.getArrayMgr('content').data;
283
					if (content.is_plain)
284
					{
285
						var plainText = this.et2.getWidgetById('mail_plaintext');
286
						// focus
287
						jQuery(plainText.node).focus();
288
						// get the cursor to the top of the textarea
289
						if (typeof plainText.node.setSelectionRange !='undefined') plainText.node.setSelectionRange(0,0);
290
					}
291
					else
292
					{
293
						textAreaWidget.ckeditor.on('instanceReady', function(e) {
294
							this.focus();
295
						});
296
					}
297
				}
298
				else if(to)
299
				{
300
					jQuery('input',to.node).focus();
301
				}
302
				break;
303
			case 'mail.subscribe':
304
				if (this.subscription_treeLastState != "")
305
				{
306
					var tree = this.et2.getWidgetById('foldertree');
307
					//Saved state of tree
308
					var state = jQuery.parseJSON(this.subscription_treeLastState);
309
310
					tree.input.loadJSONObject(tree._htmlencode_node(state));
311
				}
312
				break;
313
			case 'mail.folder_management':
314
				this.egw.message(this.egw.lang('If you would like to select multiple folders in one action, you can hold ctrl key then select a folder as start range and another folder within a same level as end range, all folders in between will be selected or unselected based on their current status.'),'info','mail:folder_management');
315
				break;
316
			case 'mail.view':
317
				// we need to set mail_currentlyFocused var otherwise mail
318
				// defined actions won't work
319
				this.mail_currentlyFocussed = this.et2.mail_currentlyFocussed;
320
321
		}
322
	},
323
324
	/**
325
	 * Observer method receives update notifications from all applications
326
	 *
327
	 * App is responsible for only reacting to "messages" it is interested in!
328
	 *
329
	 * @param {string} _msg message (already translated) to show, eg. 'Entry deleted'
330
	 * @param {string} _app application name
331
	 * @param {(string|number)} _id id of entry to refresh or null
332
	 * @param {string} _type either 'update', 'edit', 'delete', 'add' or null
333
	 * - update: request just modified data from given rows.  Sorting is not considered,
334
	 *		so if the sort field is changed, the row will not be moved.
335
	 * - edit: rows changed, but sorting may be affected.  Requires full reload.
336
	 * - delete: just delete the given rows clientside (no server interaction neccessary)
337
	 * - add: requires full reload for proper sorting
338
	 * @param {string} _msg_type 'error', 'warning' or 'success' (default)
339
	 * @param {object|null} _links app => array of ids of linked entries
340
	 * or null, if not triggered on server-side, which adds that info
341
	 * @return {false|*} false to stop regular refresh, thought all observers are run
342
	 */
343
	observer: function(_msg, _app, _id, _type, _msg_type, _links)
344
	{
345
		switch(_app)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
346
		{
347
			case 'mail':
348
				if (_id === 'sieve')
349
				{
350
					var iframe = this.et2.getWidgetById('extra_iframe');
351
					if (iframe && iframe.getDOMNode())
352
					{
353
						var contentWindow = iframe.getDOMNode().contentWindow;
354
						if (contentWindow && contentWindow.app && contentWindow.app.mail)
355
						{
356
							contentWindow.app.mail.sieve_refresh();
357
						}
358
					}
359
					return false;	// mail nextmatch needs NOT to be refreshed
360
				}
361
				break;
362
363
			case 'emailadmin':	// update tree with given mail account _id and _type
364
				var tree = this.et2 ? this.et2.getWidgetById(this.nm_index+'[foldertree]') : null;
365
				if (!tree) break;
366
				var node = tree.getNode(_id);
367
				switch(_type)
368
				{
369
					case 'delete':
370
						if (node)	// we dont care for deleted accounts not shown (eg. other users)
371
						{
372
							tree.deleteItem(_id);
373
							// ToDo: blank list, if _id was active account
374
						}
375
						break
376
					case 'update':
377
					case 'edit':
378
						if (node)	// we dont care for updated accounts not shown (eg. other users)
379
						{
380
							//tree.refreshItem(_id);
381
							egw.json('mail.mail_ui.ajax_reloadNode',[_id])
382
								.sendRequest(true);
383
						}
384
						break;
385
					case 'add':
386
						tree.refreshItem(0);	// refresh root
387
						break;
388
					default: // null
389
				}
390
		}
391
		return undefined;
392
	},
393
394
	/**
395
	 * Callback function for dataFetch caching.
396
	 *
397
	 * We only cache the first chunk (50 rows), and only if search filter is not set,
398
	 * but we cache this for every combination of folder, filter & filter2.
399
	 *
400
	 * We do not cache, if we dont find selectedFolder in query_context,
401
	 * as looking it up in tree causes mails to be cached for wrong folder
402
	 * (Probably because user already clicked on an other folder)!
403
	 *
404
	 * @param {object} query_context Query information from egw.dataFetch()
405
	 * @returns {string|false} Cache key, or false to not cache
406
	 */
407
	nm_cache: function(query_context)
408
	{
409
		// Only cache first chunk of rows, if no search filter
410
		if((!query_context || !query_context.start) && query_context.count == 0 &&
411
			query_context.filters && query_context.filters.selectedFolder &&
412
			!(!query_context.filters || query_context.filters.search)
413
		)
414
		{
415
			// Make sure keys match, even if some filters are not defined
416
			// using JSON.stringfy() directly gave a crash in Safari 7.0.4
417
			return this.egw.jsonEncode({
418
				selectedFolder: query_context.filters.selectedFolder || '',
419
				cat_id: query_context.filters.cat_id || '',
420
				filter: query_context.filters.filter || '',
421
				filter2: query_context.filters.filter2 || '',
422
				sort: query_context.filters.sort
423
			});
424
		}
425
		return false;
426
	},
427
428
	/**
429
	 * mail rebuild Action menu On nm-list
430
	 *
431
	 * @param _actions
432
	 */
433
	mail_rebuildActionsOnList: function(_actions)
434
	{
435
		this.et2.getWidgetById(this.nm_index).set_actions(_actions);
436
	},
437
438
	/**
439
	 * mail_fetchCurrentlyFocussed - implementation to decide wich mail of all the selected ones is the current
440
	 *
441
	 * @param _selected array of the selected mails
442
	 * @param _reset bool - tell the function to reset the global vars used
443
	 */
444
	mail_fetchCurrentlyFocussed: function(_selected, _reset) {
445
		// reinitialize the buffer-info on selected mails
446
		if (_reset == true || typeof _selected == 'undefined')
447
		{
448
			if (_reset == true)
449
			{
450
				// Request updated data, if possible
451
				if (this.mail_currentlyFocussed!='') egw.dataRefreshUID(this.mail_currentlyFocussed);
452
				for(var k = 0; k < this.mail_selectedMails.length; k++) egw.dataRefreshUID(this.mail_selectedMails[k]);
453
				//nm.refresh(this.mail_selectedMails,'delete');
454
			}
455
			this.mail_selectedMails = [];
456
			this.mail_currentlyFocussed = '';
457
			return '';
458
		}
459
		for(var k = 0; k < _selected.length; k++)
460
		{
461
			if (jQuery.inArray(_selected[k],this.mail_selectedMails)==-1)
462
			{
463
				this.mail_currentlyFocussed = _selected[k];
464
				break;
465
			}
466
		}
467
		this.mail_selectedMails = _selected;
468
		return this.mail_currentlyFocussed;
469
	},
470
471
	/**
472
	 * mail_open - implementation of the open action
473
	 *
474
	 * @param _action
475
	 * @param _senders - the representation of the elements(s) the action is to be performed on
476
	 * @param _mode - you may pass the mode. if not given view is used (tryastext|tryashtml are supported)
477
	 */
478
	mail_open: function(_action, _senders, _mode) {
479
		if (typeof _senders == 'undefined' || _senders.length==0)
480
		{
481
			if (this.et2.getArrayMgr("content").getEntry('mail_id'))
482
			{
483
				var _senders = [];
484
				_senders.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
485
			}
486
			if ((typeof _senders == 'undefined' || _senders.length==0) && this.mail_isMainWindow)
487
			{
488
				if (this.mail_currentlyFocussed)
489
				{
490
					var _senders = [];
491
					_senders.push({id:this.mail_currentlyFocussed});
492
				}
493
			}
494
		}
495
		var _id = _senders[0].id;
496
		// reinitialize the buffer-info on selected mails
497
		if (!(_mode == 'tryastext' || _mode == 'tryashtml' || _mode == 'view' || _mode == 'print')) _mode = 'view';
498
		this.mail_selectedMails = [];
499
		this.mail_selectedMails.push(_id);
500
		this.mail_currentlyFocussed = _id;
501
502
		var dataElem = egw.dataGetUIDdata(_id);
503
		var subject = dataElem.data.subject;
504
		//alert('Open Message:'+_id+' '+subject);
505
		var h = egw().open( _id,'mail','view',_mode+'='+_id.replace(/=/g,"_")+'&mode='+_mode);
506
		egw(h).ready(function() {
507
			h.document.title = subject;
508
		});
509
		// THE FOLLOWING IS PROBABLY NOT NEEDED, AS THE UNEVITABLE PREVIEW IS HANDLING THE COUNTER ISSUE
510
		var messages = {};
511
		messages['msg'] = [_id];
512
		// When body is requested, mail is marked as read by the mail server.  Update UI to match.
513
		if (typeof dataElem != 'undefined' && typeof dataElem.data != 'undefined' && typeof dataElem.data.flags != 'undefined' && typeof dataElem.data.flags.read != 'undefined') dataElem.data.flags.read = 'read';
514
		if (typeof dataElem != 'undefined' && typeof dataElem.data != 'undefined' && typeof dataElem.data['class'] != 'undefined' && (dataElem.data['class'].indexOf('unseen') >= 0 || dataElem.data['class'].indexOf('recent') >= 0))
515
		{
516
			this.mail_removeRowClass(messages,'recent');
517
			this.mail_removeRowClass(messages,'unseen');
518
			// reduce counter without server roundtrip
519
			this.mail_reduceCounterWithoutServerRoundtrip();
520
			// not needed, as an explizit read flags the message as seen anyhow
521
			//egw.jsonq('mail.mail_ui.ajax_flagMessages',['read', messages, false]);
522
		}
523
	},
524
525
	/**
526
	 * Open a single message in html mode
527
	 *
528
	 * @param _action
529
	 * @param _elems _elems[0].id is the row-id
530
	 */
531
	mail_openAsHtml: function(_action, _elems)
532
	{
533
		this.mail_open(_action, _elems,'tryashtml');
534
	},
535
536
	/**
537
	 * Open a single message in plain text mode
538
	 *
539
	 * @param _action
540
	 * @param _elems _elems[0].id is the row-id
541
	 */
542
	mail_openAsText: function(_action, _elems)
543
	{
544
		this.mail_open(_action, _elems,'tryastext');
545
	},
546
547
	/**
548
	 * Compose, reply or forward a message
549
	 *
550
	 * @function
551
	 * @memberOf mail
552
	 * @param _action _action.id is 'compose', 'composeasnew', 'reply', 'reply_all' or 'forward' (forward can be multiple messages)
553
	 * @param _elems _elems[0].id is the row-id
554
	 */
555
	mail_compose: function(_action, _elems)
556
	{
557
		if (typeof _elems == 'undefined' || _elems.length==0)
558
		{
559
			if (this.et2 && this.et2.getArrayMgr("content").getEntry('mail_id'))
560
			{
561
				var _elems = [];
562
				_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
563
			}
564
			if ((typeof _elems == 'undefined' || _elems.length==0) && this.mail_isMainWindow)
565
			{
566
				if (this.mail_currentlyFocussed)
567
				{
568
					var _elems = [];
569
					_elems.push({id:this.mail_currentlyFocussed});
570
				}
571
			}
572
		}
573
		// Extra info passed to egw.open()
574
		var settings = {
575
			// 'Source' Mail UID
576
			id: '',
577
			// How to pull data from the Mail IDs for the compose
578
			from: ''
579
		};
580
581
		// We only handle one for everything but forward
582
		settings.id = (typeof _elems == 'undefined'?'':_elems[0].id);
583
584
		switch(_action.id)
585
		{
586
			case 'compose':
587
				if (_elems.length == 1)
588
				{
589
					//mail_parentRefreshListRowStyle(settings.id,settings.id);
590
				}
591
				else
592
				{
593
					return this.mail_compose('forward',_elems);
594
				}
595
				break;
596
			case 'forward':
597
			case 'forwardinline':
598
			case 'forwardasattach':
599
				if (_elems.length>1||_action.id == 'forwardasattach')
600
				{
601
					settings.from = 'forward';
602
					settings.mode = 'forwardasattach';
603
					if (typeof _elems != 'undefined' && _elems.length>1)
604
					{
605
						for(var j = 1; j < _elems.length; j++)
606
						settings.id = settings.id + ',' + _elems[j].id;
607
					}
608
				}
609
				else
610
				{
611
					settings.from = 'forward';
612
					settings.mode = 'forwardinline';
613
				}
614
				break;
615
			default:
616
				// No further client side processing needed for these
617
				settings.from = _action.id;
618
		}
619
		var compose_list = egw.getOpenWindows("mail", /^compose_/);
620
		var window_name = 'compose_' + compose_list.length + '_'+ (settings.from || '') + '_' + settings.id;
621
		return egw().open('','mail','add',settings,window_name,'mail');
622
	},
623
624
	/**
625
	 * Set content into a compose window
626
	 *
627
	 * @function
628
	 * @memberOf mail
629
	 *
630
	 * @param {String} window_name The name of an open content window.
631
	 * @param {object} content
632
	 *
633
	 * @description content Data to set into the window's fields
634
	 * content.to Addresses to add to the to line
635
	 * content.cc Addresses to add to the CC line
636
	 * content.bcc Addresses to add to the BCC line
637
	 *
638
	 * @return {boolean} Success
639
	 */
640
	setCompose: function(window_name, content)
641
	{
642
		// Get window
643
		var compose = window.open('', window_name);
644
		if(!compose || compose.closed) return false;
645
646
		// Get etemplate of popup
647
		var compose_et2 = compose.etemplate2.getByApplication('mail');
648
		if(!compose_et2 || compose_et2.length != 1 || !compose_et2[0].widgetContainer)
649
		{
650
			return false;
651
		}
652
653
		// Set each field provided
654
		var success = true;
655
		var arrContent = [];
656
		for(var field in content)
657
		{
658
			try
659
			{
660
				var widget = compose_et2[0].widgetContainer.getWidgetById(field);
661
662
				// Merge array values, replace strings
663
				var value = widget.getValue() || content[field];
664
				if(jQuery.isArray(value))
665
				{
666
					if(jQuery.isArray(content[field]))
667
					{
668
						value.concat(content[field]);
669
					}
670
					else
671
					{
672
						arrContent = content[field].split(',');
673
						for (var k=0;k < arrContent.length;k++)
674
						{
675
							value.push(arrContent[k]);
676
						}
677
					}
678
				}
679
				widget.set_value(value);
680
			}
681
			catch(e)
682
			{
683
				egw.log("error", "Unable to set field %s to '%s' in window '%s'", field, content[field],window_name);
684
				success = false;
685
				continue;
0 ignored issues
show
Unused Code introduced by
This continue has no effect on the loop flow and can be removed.
Loading history...
686
			}
687
		}
688
		if (content['cc'] || content['bcc'])
689
		{
690
			this.compose_fieldExpander();
691
			this.compose_fieldExpander_init();
692
		}
693
		return success;
694
	},
695
696
	/**
697
	 * mail_disablePreviewArea - implementation of the disablePreviewArea action
698
	 *
699
	 * @param _value
700
	 */
701
	mail_disablePreviewArea: function(_value) {
702
		var splitter = this.et2.getWidgetById('mailSplitter');
703
		// return if there's no splitter we maybe in mobile mode
704
		if (typeof splitter == 'undefined' || splitter == null) return;
705
		if(splitter.isDocked())
706
		{
707
			this.mail_previewAreaActive = false;
708
		}
709
		this.et2.getWidgetById('mailPreview').set_disabled(_value);
710
		//Dock the splitter always if we are browsing with mobile
711
		if (_value==true)
712
		{
713
			if (this.mail_previewAreaActive) splitter.dock();
714
			this.mail_previewAreaActive = false;
715
		}
716
		else
717
		{
718
			if (!this.mail_previewAreaActive)
719
			{
720
				splitter.undock();
721
				window.setTimeout(function(){splitter.left.trigger('resize.et2_split.mailSplitter');},200);
722
			}
723
			this.mail_previewAreaActive = true;
724
		}
725
	},
726
727
	/**
728
	 * Create an expand on click box
729
	 *
730
	 * @param {object} _expContent an object with at least these elements
731
	 *					{build_children, data_one, data, widget, line}
732
	 *
733
	 * @param {object} _dataElem includes data of the widget which need to be expand
734
	 * @param {object} widget container of relevant template, default is this.et2
0 ignored issues
show
Documentation introduced by
The parameter widget does not exist. Did you maybe forget to remove this comment?
Loading history...
735
	 *
736
	 * @return _dataElem content of widgets
737
	 */
738
	url_email_expandOnClick: function (_expContent, _dataElem, _et2)
739
	{
740
741
		var et2 = _et2 || this.et2;
742
		for(var j = 0; j < _expContent.length; j++)
743
		{
744
			var field = _expContent[j] || [];
745
			var content = _dataElem.data[field.data] || [];
746
747
			// Add in single address, if there
748
			if(typeof field.data_one != 'undefined' && field.data != field.data_one)
749
			{
750
				if (jQuery.isArray(_dataElem.data[field.data_one]))
751
					content = content.concat(_dataElem.data[field.data_one]);
752
				else
753
					content.unshift(_dataElem.data[field.data_one]);
754
				// Unique
755
				content = content.filter(function(value, index, self) {
756
					return self.indexOf(value) === index;
757
				});
758
			}
759
760
			// Disable whole box if there are none
761
			var line = et2.getWidgetById(field.line);
762
			if(line != null) line.set_disabled(content.length == 0);
763
764
			var widget = et2.getWidgetById(field.widget);
765
			if(widget == null) continue;
766
			jQuery(widget.getDOMNode()).removeClass('visible');
767
768
			// Programatically build the child elements
769
			if(field.build_children)
770
			{
771
				// Remove any existing
772
				var children = widget.getChildren();
773
				for(var i = children.length-1; i >= 0; i--)
774
				{
775
					children[i].destroy();
776
					widget.removeChild(children[i]);
777
				}
778
				if (content.length == 1 && typeof content[0] != 'undefined' && content[0])
779
				{
780
					content = content[0].split(',');
781
				}
782
				// Add for current record
783
				var remembervalue = '';
784
				for(var i = 0; i < content.length; i++)
785
				{
786
					if (typeof content[i] != 'string' || !content[i]) continue;
787
					// if there is no @ in string, its most likely that we have a comma in the personal name part of the emailaddress
788
					if (content[i].indexOf('@')< 0)
789
					{
790
						remembervalue = content[i];
791
					}
792
					else
793
					{
794
						var value = remembervalue+(remembervalue?',':'')+content[i];
795
						var url_email_options = {
796
							id:widget.id+'_'+i,
797
							value:value,
798
							readonly:true,
799
							contact_plus:true,
800
							full_email:typeof field['full_email'] !='undefined'?field['full_email']:true
801
						};
802
						var email = et2_createWidget('url-email',url_email_options,widget);
803
						email.loadingFinished();
804
						remembervalue = '';
805
					}
806
				}
807
			}
808
			else
809
			{
810
				widget.set_value({content: content});
811
			}
812
813
			// Show or hide button, as needed
814
			line.iterateOver(function(button) {
815
				// Avoid binding to any child buttons
816
				if(button.getParent() != line) return;
0 ignored issues
show
Bug introduced by
The variable line is changed as part of the for loop for example by et2.getWidgetById(field.line) on line 761. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
817
				button.set_disabled(
818
					// Disable if only 1 address
819
					content.length <=1 || (
0 ignored issues
show
Bug introduced by
The variable content is changed as part of the for loop for example by content.0.split(",") on line 780. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
820
					// Disable if all content is visible
821
					jQuery(widget.getDOMNode()).innerWidth() >= widget.getDOMNode().scrollWidth &&
0 ignored issues
show
Bug introduced by
The variable widget is changed as part of the for loop for example by et2.getWidgetById(field.widget) on line 764. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
822
					jQuery(widget.getDOMNode()).innerHeight() >= widget.getDOMNode().scrollHeight)
823
				);
824
			},this,et2_button);
825
		}
826
827
		return _dataElem;
828
	},
829
830
	/**
831
	 * Set values for mail dispaly From,Sender,To,Cc, and Bcc
832
	 * Additionally, apply expand on click feature on thier widgets
833
	 *
834
	 */
835
	mail_display: function()
836
	{
837
		var dataElem = {data:{FROM:"",SENDER:"",TO:"",CC:"",BCC:""}};
838
		var content = this.et2.getArrayMgr('content').data;
839
		var expand_content = [
840
			{build_children: true, data_one: 'FROM', data: 'FROM', widget: 'FROM', line: 'mailDisplayHeadersFrom', full_email:false},
841
			{build_children: true,  data: 'SENDER', widget: 'SENDER', line: 'mailDisplayHeadersSender'},
842
			{build_children: true, data: 'TO', widget: 'TO', line: 'mailDisplayHeadersTo'},
843
			{build_children: true, data: 'CC', widget: 'CC', line: 'mailDisplayHeadersCc'},
844
			{build_children: true, data: 'BCC', widget:'BCC', line: 'mailDisplayHeadersBcc'}
845
		];
846
847
		if (typeof  content != 'undefiend')
848
		{
849
			dataElem.data = jQuery.extend(dataElem.data, content);
850
851
			this.url_email_expandOnClick(expand_content, dataElem);
852
			var toolbaractions = ((typeof dataElem != 'undefined' && typeof dataElem.data != 'undefined' && typeof dataElem.data.displayToolbaractions != 'undefined')?JSON.parse(dataElem.data.displayToolbaractions):undefined);
853
			if (toolbaractions) this.et2.getWidgetById('displayToolbar').set_actions(toolbaractions);
854
		}
855
	},
856
857
	/**
858
	 * mail_preview - implementation of the preview action
859
	 *
860
	 * @param nextmatch et2_nextmatch The widget whose row was selected
861
	 * @param selected Array Selected row IDs.  May be empty if user unselected all rows.
862
	 */
863
	mail_preview: function(selected, nextmatch) {
864
		// Empty values, just in case selected is empty (user cleared selection)
865
		//dataElem.data is populated, when available with fromaddress(string),toaddress(string),additionaltoaddress(array),ccaddress (array)
866
		var dataElem = {data:{subject:"",fromaddress:"",toaddress:"",ccaddress:"",date:"",attachmentsBlock:""}};
867
		var attachmentArea = this.et2.getWidgetById('previewAttachmentArea');
868
		if(typeof selected != 'undefined' && selected.length == 1)
869
		{
870
			var _id = this.mail_fetchCurrentlyFocussed(selected);
871
			dataElem = jQuery.extend(dataElem, egw.dataGetUIDdata(_id));
872
873
			// Try to resolve winmail.data attachment
874
			if (dataElem.data && dataElem.data.attachmentsBlock[0]
875
					&& dataElem.data.attachmentsBlock[0].winmailFlag
876
					&& (dataElem.data.attachmentsBlock[0].mimetype =='application/ms-tnef' ||
877
					dataElem.data.attachmentsBlock[0].filename == "winmail.dat"))
878
			{
879
				attachmentArea.getDOMNode().classList.add('loading');
880
				this.egw.jsonq('mail.mail_ui.ajax_resolveWinmail',[_id], jQuery.proxy(function(_data){
881
					attachmentArea.getDOMNode().classList.remove('loading');
882
					if (typeof _data == 'object')
883
					{
884
						attachmentArea.set_value({content:_data});
885
886
						this.data.attachmentsBlock = _data;
887
						// Update client cache to avoid resolving winmail.dat attachment again
888
						egw.dataStoreUID(this.data.uid, this.data);
889
890
						set_prev_iframe_top();
891
					}
892
					else
893
					{
894
						console.log('Can not resolve the winmail.data!');
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
895
					}
896
				},dataElem));
897
			}
898
		}
899
900
		var $preview_iframe = jQuery('#mail-index_mailPreviewContainer');
901
902
		// Re calculate the position of preview iframe according to its visible sibilings
903
		var set_prev_iframe_top = function ()
904
		{
905
			// Need to make sure that the iframe is fullyLoad before calculation
906
			window.setTimeout(function(){
907
				var lastEl = $preview_iframe.prev().prev();
908
				// Top offset of preview iframe calculated from top level
909
				var iframeTop = $preview_iframe.offset().top;
910
				while (lastEl.css('display') === "none")
911
				{
912
					lastEl = lastEl.prev();
913
				}
914
				var offset = iframeTop - (lastEl.offset().top + lastEl.height()) || 130; // fallback to 130 px if can not calculate new top
915
916
				// preview iframe parent has position absolute, therefore need to calculate the top via position
917
				$preview_iframe.css ('top', $preview_iframe.position().top - offset + 10);
918
			}, 50);
919
		};
920
921
		// Show / hide 'Select something' in preview
922
		var blank = this.et2.getWidgetById('blank');
923
		if(blank)
924
		{
925
			blank.set_disabled(true);
926
		}
927
		if (attachmentArea && typeof _id != 'undefined' && _id !='' && typeof dataElem !== 'undefined')
0 ignored issues
show
Bug introduced by
The variable _id does not seem to be initialized in case typeof selected != "und...&& selected.length == 1 on line 868 is false. Are you sure this can never be the case?
Loading history...
928
		{
929
			// If there is content to show recalculate the size
930
			set_prev_iframe_top();
931
		}
932
		else if (this.egw.preference('previewPane', 'mail') == 'fixed')
933
		{
934
			if(blank)
935
			{
936
				blank.set_disabled(false);
937
			}
938
			this.mail_disablePreviewArea(false);
939
			if (!egwIsMobile())return;
940
		}
941
		else
942
		{
943
			// Leave if we're here and there is nothing selected, too many, or no data
944
			var prevAttchArea = this.et2.getWidgetById('previewAttachmentArea');
945
			if (prevAttchArea)
946
			{
947
				prevAttchArea.set_value({content:[]});
948
				this.et2.getWidgetById('previewAttachmentArea').set_class('previewAttachmentArea noContent mail_DisplayNone');
949
				var IframeHandle = this.et2.getWidgetById('messageIFRAME');
950
				IframeHandle.set_src('about:blank');
951
				this.mail_disablePreviewArea(true);
952
			}
953
			if (!egwIsMobile())return;
954
		}
955
		// Not applied to mobile preview
956
		if (!egwIsMobile())
957
		{
958
959
			// Widget ID:data key map of widgets we can directly set from cached data
960
			var data_widgets = {
961
				'previewFromAddress':	'fromaddress',
962
				'previewDate':			'date',
963
				'previewSubject':		'subject'
964
			};
965
966
			// Set widget values from cached data
967
			for(var id in data_widgets)
968
			{
969
				var widget = this.et2.getWidgetById(id);
970
				if(widget == null) continue;
971
				widget.set_value(dataElem.data[data_widgets[id]] || "");
972
			}
973
974
			// Blank first, so we don't show previous email while loading
975
			var IframeHandle = this.et2.getWidgetById('messageIFRAME');
976
			IframeHandle.set_src('about:blank');
977
978
			// show iframe, in case we hide it from mailvelopes one and remove that
979
			jQuery(IframeHandle.getDOMNode()).show()
980
				.next(this.mailvelope_iframe_selector).remove();
981
982
			// Set up additional content that can be expanded.
983
			// We add a new URL widget for each address, so they get all the UI
984
			// TO addresses have the first one split out, not all together
985
			// list of keys:
986
			var expand_content = [
987
				{build_children: true, data_one: 'toaddress', data: 'additionaltoaddress', widget: 'additionalToAddress', line: 'mailPreviewHeadersTo'},
988
				{build_children: true, data: 'ccaddress', widget: 'additionalCCAddress', line: 'mailPreviewHeadersCC'},
989
				{build_children: false, data: 'attachmentsBlock', widget:'previewAttachmentArea', line: 'mailPreviewHeadersAttachments'}
990
			];
991
992
			// Undock the preview before running expandOnClick, because we
993
			// need to have the DOM ready for calculation.
994
			this.mail_disablePreviewArea(false);
995
996
			dataElem = this.url_email_expandOnClick(expand_content,dataElem);
997
998
			// Update the internal list of selected mails, if needed
999
			if(this.mail_selectedMails.indexOf(_id) < 0)
1000
			{
1001
				this.mail_selectedMails.push(_id);
1002
			}
1003
1004
			// Request email body from server
1005
			IframeHandle.set_src(egw.link('/index.php',{menuaction:'mail.mail_ui.loadEmailBody',_messageID:_id}));
1006
		}
1007
1008
		var messages = {};
1009
		messages['msg'] = [_id];
1010
1011
		// When body is requested, mail is marked as read by the mail server.  Update UI to match.
1012
		if (typeof dataElem != 'undefined' && typeof dataElem.data != 'undefined' && typeof dataElem.data.flags != 'undefined' && typeof dataElem.data.flags.read != 'undefined') dataElem.data.flags.read = 'read';
1013
		if (typeof dataElem != 'undefined' && typeof dataElem.data != 'undefined' && typeof dataElem.data['class']  != 'undefined' && (dataElem.data['class'].indexOf('unseen') >= 0 || dataElem.data['class'].indexOf('recent') >= 0))
1014
		{
1015
			this.mail_removeRowClass(messages,'recent');
1016
			this.mail_removeRowClass(messages,'unseen');
1017
			// reduce counter without server roundtrip
1018
			this.mail_reduceCounterWithoutServerRoundtrip();
1019
			if (typeof dataElem.data.dispositionnotificationto != 'undefined' && dataElem.data.dispositionnotificationto &&
1020
				typeof dataElem.data.flags.mdnsent == 'undefined' && typeof dataElem.data.flags.mdnnotsent == 'undefined')
1021
			{
1022
				var buttons = [
1023
					{text: this.egw.lang("Yes"), id: "mdnsent"},
1024
					{text: this.egw.lang("No"), id:"mdnnotsent"}
1025
				];
1026
				et2_dialog.show_dialog(function(_button_id, _value) {
1027
					switch (_button_id)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
1028
					{
1029
						case "mdnsent":
1030
							egw.jsonq('mail.mail_ui.ajax_sendMDN',[messages]);
1031
							egw.jsonq('mail.mail_ui.ajax_flagMessages',['mdnsent', messages, true]);
1032
							return;
1033
						case "mdnnotsent":
1034
							egw.jsonq('mail.mail_ui.ajax_flagMessages',['mdnnotsent', messages, true]);
1035
					}
1036
				},
1037
				this.egw.lang("The message sender has requested a response to indicate that you have read this message. Would you like to send a receipt?"),
1038
				this.egw.lang("Confirm"),
1039
				messages, buttons);
1040
			}
1041
			egw.jsonq('mail.mail_ui.ajax_flagMessages',['read', messages, false]);
1042
		}
1043
	},
1044
1045
	/**
1046
	 * If a preview header is partially hidden, this is the handler for clicking the
1047
	 * expand button that shows all the content for that header.
1048
	 * The button must be directly after the widget to be expanded in the template.
1049
	 * The widget to be expended is set in the event data.
1050
	 *
1051
	 * requires: mainWindow, one mail selected for preview
1052
	 *
1053
	 * @param {jQuery event} event
1054
	 * @param {Object} widget
1055
	 * @param {DOMNode} button
1056
	 */
1057
	showAllHeader: function(event,widget,button) {
1058
		// Show list as a list
1059
		var list = jQuery(button).prev();
1060
	/*	if (list.length <= 0)
1061
		{
1062
			list = jQuery(button.target).prev();
1063
		}*/
1064
1065
		list.toggleClass('visible');
1066
1067
		// Revert if user clicks elsewhere
1068
		jQuery('body').one('click', list, function(ev) {
1069
			ev.data.removeClass('visible');
1070
		});
1071
	},
1072
1073
	mail_setMailBody: function(content) {
1074
		var IframeHandle = this.et2.getWidgetById('messageIFRAME');
1075
		IframeHandle.set_value('');
1076
	},
1077
1078
	/**
1079
	 * mail_refreshFolderStatus, function to call to read the counters of a folder and apply them
1080
	 *
1081
	 * @param {stirng} _nodeID
1082
	 * @param {string} mode
1083
	 * @param {boolean} _refreshGridArea
1084
	 * @param {boolean} _refreshQuotaDisplay
1085
	 *
1086
	 */
1087
	mail_refreshFolderStatus: function(_nodeID,mode,_refreshGridArea,_refreshQuotaDisplay) {
1088
		if (typeof _nodeID != 'undefined' && typeof _nodeID[_nodeID] != 'undefined' && _nodeID[_nodeID])
1089
		{
1090
			_refreshGridArea = _nodeID[_refreshGridArea];
1091
			mode = _nodeID[mode];
1092
			_nodeID = _nodeID[_nodeID];
1093
		}
1094
		var nodeToRefresh = 0;
1095
		var mode2use = "none";
1096
		if (typeof _refreshGridArea == 'undefined') _refreshGridArea=true;
1097
		if (typeof _refreshQuotaDisplay == 'undefined') _refreshQuotaDisplay=true;
1098
		if (_nodeID) nodeToRefresh = _nodeID;
1099
		if (mode) {
1100
			if (mode == "forced") {mode2use = mode;}
1101
		}
1102
		try
1103
		{
1104
			var tree_wdg = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1105
1106
			var activeFolders = tree_wdg.getTreeNodeOpenItems(nodeToRefresh,mode2use);
1107
			//alert(activeFolders.join('#,#'));
1108
			this.mail_queueRefreshFolderList((mode=='thisfolderonly'&&nodeToRefresh?[_nodeID]:activeFolders));
1109
			if (_refreshGridArea)
1110
			{
1111
				// maybe to use the mode forced as trigger for grid reload and using the grids own autorefresh
1112
				// would solve the refresh issue more accurately
1113
				//if (mode == "forced") this.mail_refreshMessageGrid();
1114
				this.mail_refreshMessageGrid();
1115
			}
1116
			if (_refreshQuotaDisplay)
1117
			{
1118
				this.mail_refreshQuotaDisplay();
1119
			}
1120
			//the two lines below are not working yet.
1121
			//var no =tree_wdg.getSelectedNode();
1122
			//tree_wdg.focusItem(no.id);
1123
		} catch(e) { } // ignore the error; maybe the template is not loaded yet
1124
	},
1125
1126
	/**
1127
	 * mail_refreshQuotaDisplay, function to call to read the quota for the active server
1128
	 *
1129
	 * @param {object} _server
1130
	 *
1131
	 */
1132
	mail_refreshQuotaDisplay: function(_server)
1133
	{
1134
		egw.json('mail.mail_ui.ajax_refreshQuotaDisplay',[_server])
1135
			.sendRequest(true);
1136
	},
1137
1138
	/**
1139
	 * mail_setQuotaDisplay, function to call to read the quota for the active server
1140
	 *
1141
	 * @param {object} _data
1142
	 *
1143
	 */
1144
	mail_setQuotaDisplay: function(_data)
1145
	{
1146
		if (!this.et2 && !this.checkET2()) return;
1147
1148
		var quotabox = this.et2.getWidgetById(this.nm_index+'[quotainpercent]');
1149
1150
		// Check to make sure it's there
1151
		if(quotabox)
1152
		{
1153
			//try to set it via set_value and set label
1154
			quotabox.set_class(_data.data.quotaclass);
1155
			quotabox.set_value(_data.data.quotainpercent);
1156
			quotabox.set_label(_data.data.quota);
1157
			if (_data.data.quotawarning)
1158
			{
1159
				var self = this;
1160
				var buttons = [
1161
					{text: this.egw.lang("Empty Trash and Junk"), id: "cleanup", class: "ui-priority-primary", default: true, image:"delete"},
1162
					{text: this.egw.lang("Cancel"), id:"cancel"}
1163
				];
1164
				var server = [{iface:{id: _data.data.profileid+'::'}}];
1165
				et2_dialog.show_dialog(function(_button_id) {
1166
					if (_button_id == "cleanup")
1167
					{
1168
						self.mail_emptySpam (null, server);
1169
						self.mail_emptyTrash (null, server);
1170
					}
1171
					return;
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
1172
				},
1173
				this.egw.lang("Your mail quota is %1% full, you may not be able to send/receive further emails.\n Although cleaning up emails in trash or junk folder might help you to get some free space back.\n If that didn't help, please ask administrator for more quota.", _data.data.quotainpercent),
1174
				this.egw.lang("Mail cleanup"),
1175
				'', buttons, et2_dialog.WARNING_MESSAGE);
1176
			}
1177
		}
1178
	},
1179
1180
	/**
1181
	 * mail_callRefreshVacationNotice, function to call the serverside function to refresh the vacationnotice for the active server
1182
	 *
1183
	 * @param {object} _server
1184
	 *
1185
	 */
1186
	mail_callRefreshVacationNotice: function(_server)
1187
	{
1188
		egw.jsonq('mail_ui::ajax_refreshVacationNotice',[_server]);
1189
	},
1190
	/**
1191
	 * Make sure attachments have all needed data, so they can be found for
1192
	 * HTML5 native dragging
1193
	 *
1194
	 * @param {string} mail_id Mail UID
1195
	 * @param {array} attachments Attachment information.
1196
	 */
1197
	register_for_drag: function(mail_id, attachments)
1198
	{
1199
		// Put required info in global store
1200
		var data = {};
1201
		if (!attachments) return;
1202
		for (var i = 0; i < attachments.length; i++)
1203
		{
1204
			var data = attachments[i] || {};
1205
			if(!data.filename || !data.type) continue;
1206
1207
			// Add required info
1208
			data.mime = data.type;
1209
			data.download_url = egw.link('/index.php', {
1210
				menuaction: 'mail.mail_ui.getAttachment',
1211
				id: mail_id,
1212
				part: data.partID,
1213
				is_winmail: data.winmailFlag
1214
			});
1215
			data.name = data.filename;
1216
		}
1217
	},
1218
1219
	/**
1220
	 * Display helper for dragging attachments
1221
	 *
1222
	 * @param {egwAction} _action
1223
	 * @param {egwActionElement[]} _elems
1224
	 * @returns {DOMNode}
1225
	 */
1226
	drag_attachment: function(_action, _elems)
1227
	{
1228
		var div = jQuery(document.createElement("div"))
1229
			.css({
1230
				position: 'absolute',
1231
				top: '0px',
1232
				left: '0px',
1233
				width: '300px'
1234
			});
1235
1236
		var data = _elems[0].data || {};
1237
1238
		var text = jQuery(document.createElement('div')).css({left: '30px', position: 'absolute'});
1239
		// add filename or number of files for multiple files
1240
		text.text(_elems.length > 1 ? _elems.length+' '+this.egw.lang('files') : data.name || '');
1241
		div.append(text);
1242
1243
		// Add notice of Ctrl key, if supported
1244
		if(window.FileReader && 'draggable' in document.createElement('span') &&
1245
			navigator && navigator.userAgent.indexOf('Chrome') >= 0)
1246
		{
1247
			var key = ["Mac68K","MacPPC","MacIntel"].indexOf(window.navigator.platform) < 0 ? 'Ctrl' : 'Command';
1248
			text.append('<br />' + this.egw.lang('Hold %1 to drag files to your computer',key));
1249
		}
1250
		return div;
1251
	},
1252
1253
	/**
1254
	 * mail_refreshVacationNotice, function to call with appropriate data to refresh the vacationnotice for the active server
1255
	 *
1256
	 * @param {object} _data
1257
	 *
1258
	 */
1259
	mail_refreshVacationNotice: function(_data)
1260
	{
1261
		if (!this.et2 && !this.checkET2()) return;
1262
		if (_data == null)
1263
		{
1264
			this.et2.getWidgetById(this.nm_index+'[vacationnotice]').set_value('');
1265
			this.et2.getWidgetById(this.nm_index+'[vacationrange]').set_value('');
1266
		}
1267
		else
1268
		{
1269
			this.et2.getWidgetById(this.nm_index+'[vacationnotice]').set_value(_data.vacationnotice);
1270
			this.et2.getWidgetById(this.nm_index+'[vacationrange]').set_value(_data.vacationrange);
1271
		}
1272
	},
1273
1274
	/**
1275
	 * Enable or disable the date filter
1276
	 *
1277
	 * If the searchtype (cat_id) is set to something that needs dates, we enable the
1278
	 * header_right template.  Otherwise, it is disabled.
1279
	 */
1280
	mail_searchtype_change: function()
1281
	{
1282
		var filter = this.et2.getWidgetById('cat_id');
1283
		var nm = this.et2.getWidgetById(this.nm_index);
1284
		var dates = this.et2.getWidgetById('mail.index.datefilter');
1285
		if(nm && filter)
1286
		{
1287
			switch(filter.getValue())
1288
			{
1289
				case 'bydate':
1290
1291
					if (filter && dates)
1292
					{
1293
						dates.set_disabled(false);
1294
						if (this.et2.getWidgetById('startdate')) jQuery(this.et2.getWidgetById('startdate').getDOMNode()).find('input').focus();
1295
					}
1296
					this.mail_callRefreshVacationNotice();
1297
					return true;
1298
				default:
1299
					if (dates)
1300
					{
1301
						dates.set_disabled(true);
1302
					}
1303
					this.mail_callRefreshVacationNotice();
1304
					return true;
1305
			}
1306
		}
1307
		return false;
1308
	},
1309
1310
	/**
1311
	 * mail_refreshFilter2Options, function to call with appropriate data to refresh the filter2 options for the active server
1312
	 *
1313
	 * @param {object} _data
1314
	 *
1315
	 */
1316
	mail_refreshFilter2Options: function(_data)
1317
	{
1318
		//alert('mail_refreshFilter2Options');
1319
		if (_data == null) return;
1320
		if (!this.et2 && !this.checkET2()) return;
1321
1322
		var filter2 = this.et2.getWidgetById('filter2');
1323
		var current = filter2.value;
1324
		var currentexists=false;
1325
		for (var k in _data)
1326
		{
1327
			if (k==current) currentexists=true;
1328
		}
1329
		if (!currentexists) filter2.set_value('');
1330
		filter2.set_select_options(_data);
1331
	},
1332
1333
	/**
1334
	 * mail_refreshFilterOptions, function to call with appropriate data to refresh the filter options for the active server
1335
	 *
1336
	 * @param {object} _data
1337
	 *
1338
	 */
1339
	mail_refreshFilterOptions: function(_data)
1340
	{
1341
		//alert('mail_refreshFilterOptions');
1342
		if (_data == null) return;
1343
		if (!this.et2 && !this.checkET2()) return;
1344
1345
		var filter = this.et2.getWidgetById('filter');
1346
		var current = filter.value;
1347
		var currentexists=false;
1348
		for (var k in _data)
1349
		{
1350
			if (k==current) currentexists=true;
1351
		}
1352
		if (!currentexists) filter.set_value('any');
1353
		filter.set_select_options(_data);
1354
1355
	},
1356
1357
	/**
1358
	 * mail_refreshCatIdOptions, function to call with appropriate data to refresh the filter options for the active server
1359
	 *
1360
	 * @param {object} _data
1361
	 *
1362
	 */
1363
	mail_refreshCatIdOptions: function(_data)
1364
	{
1365
		//alert('mail_refreshCatIdOptions');
1366
		if (_data == null) return;
1367
		if (!this.et2 && !this.checkET2()) return;
1368
1369
		var filter = this.et2.getWidgetById('cat_id');
1370
		var current = filter.value;
1371
		var currentexists=false;
1372
		for (var k in _data)
1373
		{
1374
			if (k==current) currentexists=true;
1375
		}
1376
		if (!currentexists) filter.set_value('quick');
1377
		filter.set_select_options(_data);
1378
1379
	},
1380
1381
	/**
1382
	 * Queues a refreshFolderList request for 500ms. Actually this will just execute the
1383
	 * code after the calling script has finished.
1384
	 *
1385
	 * @param {array} _folders description
1386
	 */
1387
	mail_queueRefreshFolderList: function(_folders)
1388
	{
1389
		var self = this;
1390
		// as jsonq is too fast wrap it to be delayed a bit, to ensure the folder actions
1391
		// are executed last of the queue
1392
		window.setTimeout(function() {
1393
			egw.jsonq('mail.mail_ui.ajax_setFolderStatus',[_folders], function (){self.unlock_tree();});
1394
		}, 500);
1395
	},
1396
1397
	/**
1398
	 * mail_CheckFolderNoSelect - implementation of the mail_CheckFolderNoSelect action to control right click options on the tree
1399
	 *
1400
	 * @param {object} action
1401
	 * @param {object} _senders the representation of the tree leaf to be manipulated
1402
	 * @param {object} _currentNode
1403
	 */
1404
	mail_CheckFolderNoSelect: function(action,_senders,_currentNode) {
1405
1406
		// Abort if user selected an un-selectable node
1407
		// Use image over anything else because...?
1408
		var ftree, node;
1409
		ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1410
		if (ftree)
1411
		{
1412
			node = ftree.getNode(_senders[0].id);
1413
		}
1414
1415
		if (node && node.im0.indexOf('NoSelect') !== -1)
1416
		{
1417
			//ftree.reSelectItem(_previous);
1418
			return false;
1419
		}
1420
1421
		return true;
1422
	},
1423
1424
	/**
1425
	 * Check if SpamFolder is enabled on that account
1426
	 *
1427
	 * SpamFolder enabled is stored as data { spamfolder: true/false } on account node.
1428
	 *
1429
	 * @param {object} _action
1430
	 * @param {object} _senders the representation of the tree leaf to be manipulated
1431
	 * @param {object} _currentNode
1432
	 */
1433
	spamfolder_enabled: function(_action,_senders,_currentNode)
1434
	{
1435
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1436
		var acc_id = _senders[0].id.split('::')[0];
1437
		var node = ftree ? ftree.getNode(acc_id) : null;
1438
1439
		return node && node.data && node.data.spamfolder;
1440
	},
1441
1442
1443
	/**
1444
	 * Check if archiveFolder is enabled on that account
1445
	 *
1446
	 * ArchiveFolder enabled is stored as data { archivefolder: true/false } on account node.
1447
	 *
1448
	 * @param {object} _action
1449
	 * @param {object} _senders the representation of the tree leaf to be manipulated
1450
	 * @param {object} _currentNode
1451
	 */
1452
	archivefolder_enabled: function(_action,_senders,_currentNode)
1453
	{
1454
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1455
		var acc_id = _senders[0].id.split('::')[2]; // this is operating on mails
1456
		var node = ftree ? ftree.getNode(acc_id) : null;
1457
1458
		return node && node.data && node.data.archivefolder;
1459
	},
1460
1461
	/**
1462
	 * Check if Sieve is enabled on that account
1463
	 *
1464
	 * Sieve enabled is stored as data { sieve: true/false } on account node.
1465
	 *
1466
	 * @param {object} _action
1467
	 * @param {object} _senders the representation of the tree leaf to be manipulated
1468
	 * @param {object} _currentNode
1469
	 */
1470
	sieve_enabled: function(_action,_senders,_currentNode)
1471
	{
1472
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1473
		var acc_id = _senders[0].id.split('::')[0];
1474
		var node = ftree ? ftree.getNode(acc_id) : null;
1475
1476
		return node && node.data && node.data.sieve;
1477
	},
1478
1479
	/**
1480
	 * Check if ACL is enabled on that account
1481
	 *
1482
	 * ACL enabled is stored as data { acl: true/false } on INBOX node.
1483
	 * We also need to check if folder is marked as no-select!
1484
	 *
1485
	 * @param {object} _action
1486
	 * @param {object} _senders the representation of the tree leaf to be manipulated
1487
	 * @param {object} _currentNode
1488
	 */
1489
	acl_enabled: function(_action,_senders,_currentNode)
1490
	{
1491
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1492
		var inbox = _senders[0].id.split('::')[0]+'::INBOX';
1493
		var node = ftree ? ftree.getNode(inbox) : null;
1494
1495
		return node && node.data && node.data.acl && this.mail_CheckFolderNoSelect(_action,_senders,_currentNode);
1496
	},
1497
1498
	/**
1499
	 * mail_setFolderStatus, function to set the status for the visible folders
1500
	 *
1501
	 * @param {array} _status
1502
	 */
1503
	mail_setFolderStatus: function(_status) {
1504
		if (!this.et2 && !this.checkET2()) return;
1505
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1506
		for (var i in _status) {
1507
			ftree.setLabel(i,_status[i]);
1508
			// display folder-name bold for unseen mails
1509
			ftree.setStyle(i, 'font-weight: '+(_status[i].match(this._unseen_regexp) ? 'bold' : 'normal'));
1510
			//alert(i +'->'+_status[i]);
1511
		}
1512
	},
1513
1514
	/**
1515
	 * mail_setLeaf, function to set the id and description for the folder given by status key
1516
	 * @param {array} _status status array with the required data (new id, desc, old desc)
1517
	 *		key is the original id of the leaf to change
1518
	 *		multiple sets can be passed to mail_setLeaf
1519
	 */
1520
	mail_setLeaf: function(_status) {
1521
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1522
		var selectedNode = ftree.getSelectedNode();
1523
		for (var i in _status)
1524
		{
1525
			// if olddesc is undefined or #skip# then skip the message, as we process subfolders
1526
			if (typeof _status[i]['olddesc'] !== 'undefined' && _status[i]['olddesc'] !== '#skip-user-interaction-message#') this.egw.message(this.egw.lang("Renamed Folder %1 to %2",_status[i]['olddesc'],_status[i]['desc']));
1527
			ftree.renameItem(i,_status[i]['id'],_status[i]['desc']);
1528
			ftree.setStyle(i, 'font-weight: '+(_status[i]['desc'].match(this._unseen_regexp) ? 'bold' : 'normal'));
1529
			//alert(i +'->'+_status[i]['id']+'+'+_status[i]['desc']);
1530
			if (_status[i]['id']==selectedNode.id)
1531
			{
1532
				var nm = this.et2.getWidgetById(this.nm_index);
1533
				nm.activeFilters["selectedFolder"] = _status[i]['id'];
1534
				nm.applyFilters();
1535
			}
1536
		}
1537
	},
1538
1539
	/**
1540
	 * mail_removeLeaf, function to remove the leaf represented by the given ID
1541
	 * @param {array} _status status array with the required data (KEY id, VALUE desc)
1542
	 *		key is the id of the leaf to delete
1543
	 *		multiple sets can be passed to mail_deleteLeaf
1544
	 */
1545
	mail_removeLeaf: function(_status) {
1546
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1547
		var selectedNode = ftree.getSelectedNode();
1548
		for (var i in _status)
1549
		{
1550
			// if olddesc is undefined or #skip# then skip the message, as we process subfolders
1551
			if (typeof _status[i] !== 'undefined' && _status[i] !== '#skip-user-interaction-message#') this.egw.message(this.egw.lang("Removed Folder %1 ",_status[i]));
1552
			ftree.deleteItem(i,(selectedNode.id==i));
1553
			var selectedNodeAfter = ftree.getSelectedNode();
1554
			//alert(i +'->'+_status[i]['id']+'+'+_status[i]['desc']);
1555
			if (selectedNodeAfter.id!=selectedNode.id && selectedNode.id==i)
1556
			{
1557
				var nm = this.et2.getWidgetById(this.nm_index);
1558
				nm.activeFilters["selectedFolder"] = selectedNodeAfter.id;
1559
				nm.applyFilters();
1560
			}
1561
		}
1562
	},
1563
1564
	/**
1565
	 * mail_reloadNode, function to reload the leaf represented by the given ID
1566
	 * @param {Object.<string,string>|Object.<string,Object}}  _status
1567
	 *		Object with the required data (KEY id, VALUE desc), or ID => {new data}
1568
	 */
1569
	mail_reloadNode: function(_status) {
1570
		var ftree = this.et2?this.et2.getWidgetById(this.nm_index+'[foldertree]'):null;
1571
		if (!ftree) return;
1572
		var selectedNode = ftree.getSelectedNode();
1573
		for (var i in _status)
1574
		{
1575
			// if olddesc is undefined or #skip# then skip the message, as we process subfolders
1576
			if (typeof _status[i] !== 'undefined' && _status[i] !== '#skip-user-interaction-message#')
1577
			{
1578
					this.egw.message(this.egw.lang((typeof _status[i].parent !== 'undefined'? "Reloaded Folder %1" : "Reloaded Account %1") ,
1579
					(typeof _status[i] == "string" ? _status[i].replace(this._unseen_regexp, '') :
1580
							(_status[i].text ? _status[i].text.replace(this._unseen_regexp, '') : _status[i].id))));
1581
			}
1582
			ftree.refreshItem(i,typeof _status[i] == "object" ? _status[i] : null);
1583
			if (typeof _status[i] == "string") ftree.setStyle(i, 'font-weight: '+(_status[i].match(this._unseen_regexp) ? 'bold' : 'normal'));
1584
		}
1585
1586
		var selectedNodeAfter = ftree.getSelectedNode();
1587
1588
		// If selected folder changed, refresh nextmatch
1589
		if (selectedNodeAfter != null && selectedNodeAfter.id!=selectedNode.id)
1590
		{
1591
			var nm = this.et2.getWidgetById(this.nm_index);
1592
			nm.activeFilters["selectedFolder"] = selectedNodeAfter.id;
1593
			nm.applyFilters();
1594
		}
1595
	},
1596
1597
	/**
1598
	 * mail_refreshMessageGrid, function to call to reread ofthe current folder
1599
	 *
1600
	 * @param {boolean} _isPopup
1601
	 */
1602
	mail_refreshMessageGrid: function(_isPopup, _refreshVacationNotice) {
1603
		if (typeof _isPopup == 'undefined') _isPopup = false;
1604
		if (typeof _refreshVacationNotice == 'undefined') _refreshVacationNotice = false;
1605
		var nm;
1606
		if (_isPopup && !this.mail_isMainWindow)
1607
		{
1608
			nm = window.opener.etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById(this.nm_index);
1609
		}
1610
		else
1611
		{
1612
			nm = this.et2.getWidgetById(this.nm_index);
1613
		}
1614
		var dates = this.et2.getWidgetById('mail.index.datefilter');
1615
		var filter = this.et2.getWidgetById('cat_id');
1616
		if(nm && filter)
1617
		{
1618
			nm.activeFilters["startdate"]=null;
1619
			nm.activeFilters["enddate"]=null;
1620
			switch(filter.getValue())
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
1621
			{
1622
				case 'bydate':
1623
1624
					if (filter && dates)
1625
					{
1626
						if (this.et2.getWidgetById('startdate') && this.et2.getWidgetById('startdate').get_value()) nm.activeFilters["startdate"] = this.et2.getWidgetById('startdate').date;
1627
						if (this.et2.getWidgetById('enddate') && this.et2.getWidgetById('enddate').get_value()) nm.activeFilters["enddate"] = this.et2.getWidgetById('enddate').date;
1628
					}
1629
			}
1630
		}
1631
		nm.applyFilters(); // this should refresh the active folder
1632
		if (_refreshVacationNotice) this.mail_callRefreshVacationNotice();
1633
	},
1634
1635
	/**
1636
	 * mail_getMsg - gets the current Message
1637
	 * @return string
1638
	 */
1639
	mail_getMsg: function()
1640
	{
1641
		var msg_wdg = this.et2.getWidgetById('msg');
1642
		if (msg_wdg)
1643
		{
1644
			return msg_wdg.valueOf().htmlNode[0].innerHTML;
1645
		}
1646
		return "";
1647
	},
1648
1649
	/**
1650
	 * mail_setMsg - sets a Message, with the msg container, and controls if the container is enabled/disabled
1651
	 * @param {string} myMsg - the message
1652
	 */
1653
	mail_setMsg: function(myMsg)
1654
	{
1655
		var msg_wdg = this.et2.getWidgetById('msg');
1656
		if (msg_wdg)
1657
		{
1658
			msg_wdg.set_value(myMsg);
1659
			msg_wdg.set_disabled(myMsg.trim().length==0);
1660
		}
1661
	},
1662
1663
	/**
1664
	 * Delete mails
1665
	 * takes in all arguments
1666
	 * @param _action
1667
	 * @param _elems
1668
	 */
1669
	mail_delete: function(_action,_elems)
1670
	{
1671
		this.mail_checkAllSelected(_action,_elems,null,true);
1672
	},
1673
1674
	/**
1675
	 * call Delete mails
1676
	 * takes in all arguments
1677
	 * @param {object} _action
1678
	 * @param {array} _elems
1679
	 * @param {boolean} _allMessagesChecked
1680
	 */
1681
	mail_callDelete: function(_action,_elems,_allMessagesChecked)
1682
	{
1683
		var calledFromPopup = false;
1684
		if (typeof _allMessagesChecked == 'undefined') _allMessagesChecked=false;
1685
		if (typeof _elems == 'undefined' || _elems.length==0)
1686
		{
1687
			calledFromPopup = true;
1688
			if (this.et2.getArrayMgr("content").getEntry('mail_id'))
1689
			{
1690
				var _elems = [];
1691
				_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
1692
			}
1693
			if ((typeof _elems == 'undefined' || _elems.length==0) && this.mail_isMainWindow)
1694
			{
1695
				if (this.mail_currentlyFocussed)
1696
				{
1697
					var _elems = [];
1698
					_elems.push({id:this.mail_currentlyFocussed});
1699
				}
1700
			}
1701
		}
1702
		var msg = this.mail_getFormData(_elems);
1703
		msg['all'] = _allMessagesChecked;
1704
		if (msg['all']=='cancel') return false;
1705
		if (msg['all']) msg['activeFilters'] = this.mail_getActiveFilters(_action);
1706
		//alert(_action.id+','+ msg);
1707
		if (!calledFromPopup) this.mail_setRowClass(_elems,'deleted');
1708
		this.mail_deleteMessages(msg,'no',calledFromPopup);
1709
		if (calledFromPopup && this.mail_isMainWindow==false)
1710
		{
1711
			egw(window).close();
1712
		}
1713
		else if (typeof this.et2_view!='undefined' && typeof this.et2_view.close == 'function')
1714
		{
1715
			this.et2_view.close();
1716
		}
1717
	},
1718
1719
	/**
1720
	 * function to find (and reduce) unseen count from folder-name
1721
	 */
1722
	mail_reduceCounterWithoutServerRoundtrip: function()
1723
	{
1724
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1725
		var _foldernode = ftree.getSelectedNode();
1726
		var counter = _foldernode.label.match(this._unseen_regexp);
1727
		var icounter = 0;
1728
		if ( counter ) icounter = parseInt(counter[0].replace(' (','').replace(')',''));
1729
		if (icounter>0)
1730
		{
1731
			var newcounter = icounter-1;
1732
			if (newcounter>0) _foldernode.label = _foldernode.label.replace(' ('+String(icounter)+')',' ('+String(newcounter)+')');
1733
			if (newcounter==0) _foldernode.label = _foldernode.label.replace(' ('+String(icounter)+')','');
1734
			ftree.setLabel(_foldernode.id,_foldernode.label);
1735
		}
1736
	},
1737
1738
	/**
1739
	 * Regular expression to find (and remove) unseen count from folder-name
1740
	 */
1741
	_unseen_regexp: / \([0-9]+\)$/,
1742
1743
	/**
1744
	 * mail_splitRowId
1745
	 *
1746
	 * @param {string} _rowID
1747
	 *
1748
	 */
1749
	mail_splitRowId: function(_rowID)
1750
	{
1751
		var res = _rowID.split('::');
1752
		// as a rowID is perceeded by app::, should be mail!
1753
		if (res.length==4 && !isNaN(parseInt(res[0])))
1754
		{
1755
			// we have an own created rowID; prepend app=mail
1756
			res.unshift('mail');
1757
		}
1758
		return res;
1759
	},
1760
1761
	/**
1762
	 * Delete mails - actually calls the backend function for deletion
1763
	 * takes in all arguments
1764
	 * @param {string} _msg - message list
1765
	 * @param {object} _action - optional action
1766
	 * @param {object} _calledFromPopup
1767
	 */
1768
	mail_deleteMessages: function(_msg,_action,_calledFromPopup)
1769
	{
1770
		var message, ftree, _foldernode, displayname;
1771
		ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1772
		if (ftree)
1773
		{
1774
			_foldernode = ftree.getSelectedNode();
1775
1776
			displayname = _foldernode.label.replace(this._unseen_regexp, '');
1777
		}
1778
		else
1779
		{
1780
			message = this.mail_splitRowId(_msg['msg'][0]);
1781
			if (message[3]) _foldernode = displayname = jQuery.base64Decode(message[3]);
1782
		}
1783
1784
		// Tell server
1785
		egw.json('mail.mail_ui.ajax_deleteMessages',[_msg,(typeof _action == 'undefined'?'no':_action)])
1786
			.sendRequest(true);
1787
1788
		if (_msg['all']) this.egw.refresh(this.egw.lang("deleted %1 messages in %2",(_msg['all']?egw.lang('all'):_msg['msg'].length),(displayname?displayname:egw.lang('current folder'))),'mail');//,ids,'delete');
1789
		this.egw.message(this.egw.lang("deleted %1 messages in %2",(_msg['all']?egw.lang('all'):_msg['msg'].length),(displayname?displayname:egw.lang('current Folder'))));
1790
	},
1791
1792
	/**
1793
	 * Delete mails show result - called from the backend function for display of deletionmessages
1794
	 * takes in all arguments
1795
	 * @param _msg - message list
1796
	 */
1797
	mail_deleteMessagesShowResult: function(_msg)
1798
	{
1799
		// Update list
1800
		var ids = [];
1801
		for (var i = 0; i < _msg['msg'].length; i++)
1802
		{
1803
			ids.push(_msg['msg'][i].replace(/mail::/,''));
1804
		}
1805
		//this.egw.message(_msg['egw_message']);
1806
		if (_msg['all'])
1807
		{
1808
			this.egw.refresh(_msg['egw_message'],'mail');
1809
		}
1810
		else
1811
		{
1812
			this.egw.refresh(_msg['egw_message'],'mail',ids,'delete');
1813
1814
			// Nextmatch automatically selects the next row and calls preview.
1815
			// Unselect it and thanks to the timeout selectionMgr uses, preview
1816
			// will close when the selection callback fires.
1817
			this.et2.getWidgetById(this.nm_index).controller._selectionMgr.resetSelection();
1818
		}
1819
	},
1820
1821
	/**
1822
	 * retry to Delete mails
1823
	 * @param responseObject ->
1824
	 * 	 reason - reason to report
1825
	 * 	 messageList
1826
	 */
1827
	mail_retryForcedDelete: function(responseObject)
1828
	{
1829
		var reason = responseObject['response'];
1830
		var messageList = responseObject['messageList'];
1831
		if (confirm(reason))
1832
		{
1833
			this.mail_deleteMessages(messageList,'remove_immediately');
1834
		}
1835
		else
1836
		{
1837
			this.egw.message(this.egw.lang('canceled deletion due to userinteraction'));
1838
			this.mail_removeRowClass(messageList,'deleted');
1839
		}
1840
		this.mail_refreshMessageGrid();
1841
		this.mail_preview();
1842
	},
1843
1844
	/**
1845
	 * UnDelete mailMessages
1846
	 *
1847
	 * @param _messageList
1848
	 */
1849
	mail_undeleteMessages: function(_messageList) {
1850
	// setting class of row, the old style
1851
	},
1852
1853
	/**
1854
	 * mail_emptySpam
1855
	 *
1856
	 * @param {object} action
1857
	 * @param {object} _senders
1858
	 */
1859
	mail_emptySpam: function(action,_senders) {
1860
		var server = _senders[0].iface.id.split('::');
1861
		var activeFilters = this.mail_getActiveFilters();
1862
		var self = this;
1863
1864
		this.egw.message(this.egw.lang('empty junk'));
1865
		egw.json('mail.mail_ui.ajax_emptySpam',[server[0], activeFilters['selectedFolder']? activeFilters['selectedFolder']:null],function(){self.unlock_tree();})
1866
			.sendRequest(true);
1867
1868
		// Directly delete any trash cache for selected server
1869
		if(window.localStorage)
1870
		{
1871
			for(var i = 0; i < window.localStorage.length; i++)
1872
			{
1873
				var key = window.localStorage.key(i);
1874
1875
				// Find directly by what the key would look like
1876
				if(key.indexOf('cached_fetch_mail::{"selectedFolder":"'+server[0]+'::') == 0 &&
1877
					key.toLowerCase().indexOf(egw.lang('junk').toLowerCase()) > 0)
1878
				{
1879
					window.localStorage.removeItem(key);
1880
				}
1881
			}
1882
		}
1883
	},
1884
1885
	/**
1886
	 * mail_emptyTrash
1887
	 *
1888
	 * @param {object} action
1889
	 * @param {object} _senders
1890
	 */
1891
	mail_emptyTrash: function(action,_senders) {
1892
		var server = _senders[0].iface.id.split('::');
1893
		var activeFilters = this.mail_getActiveFilters();
1894
		var self = this;
1895
1896
		this.egw.message(this.egw.lang('empty trash'));
1897
		egw.json('mail.mail_ui.ajax_emptyTrash',[server[0], activeFilters['selectedFolder']? activeFilters['selectedFolder']:null],function(){self.unlock_tree();})
1898
			.sendRequest(true);
1899
1900
		// Directly delete any trash cache for selected server
1901
		if(window.localStorage)
1902
		{
1903
			for(var i = 0; i < window.localStorage.length; i++)
1904
			{
1905
				var key = window.localStorage.key(i);
1906
1907
				// Find directly by what the key would look like
1908
				if(key.indexOf('cached_fetch_mail::{"selectedFolder":"'+server[0]+'::') == 0 &&
1909
					key.toLowerCase().indexOf(egw.lang('trash').toLowerCase()) > 0)
1910
				{
1911
					window.localStorage.removeItem(key);
1912
				}
1913
			}
1914
		}
1915
	},
1916
1917
	/**
1918
	 * mail_compressFolder
1919
	 *
1920
	 * @param {object} action
1921
	 * @param {object} _senders
1922
	 *
1923
	 */
1924
	mail_compressFolder: function(action,_senders) {
1925
		this.egw.message(this.egw.lang('compress folder'));
1926
		egw.jsonq('mail.mail_ui.ajax_compressFolder',[_senders[0].iface.id]);
1927
		//	.sendRequest(true);
1928
		// since the json reply is using this.egw.refresh, we should not need to call refreshFolderStatus
1929
		// as the actions thereof are now bound to run after grid refresh
1930
		//this.mail_refreshFolderStatus();
1931
	},
1932
1933
	/**
1934
	 * mail_changeProfile
1935
	 *
1936
	 * @param {string} folder the ID of the selected Node -> should be an integer
1937
	 * @param {object} _widget handle to the tree widget
1938
	 * @param {boolean} getFolders Flag to indicate that the profile needs the mail
1939
	 *		folders.  False means they're already loaded in the tree, and we don't need
1940
	 *		them again
1941
	 */
1942
	mail_changeProfile: function(folder,_widget, getFolders) {
1943
		if(typeof getFolders == 'undefined')
1944
		{
1945
			getFolders = true;
1946
		}
1947
	//	alert(folder);
1948
		this.egw.message(this.egw.lang('Connect to Profile %1',_widget.getSelectedLabel().replace(this._unseen_regexp, '')));
1949
1950
		//Open unloaded tree to get loaded
1951
		_widget.openItem(folder, true);
1952
1953
		this.lock_tree();
1954
		egw.json('mail_ui::ajax_changeProfile',[folder, getFolders, this.et2._inst.etemplate_exec_id], jQuery.proxy(function() {
1955
			// Profile changed, select inbox
1956
			var inbox = folder + '::INBOX';
1957
			_widget.reSelectItem(inbox);
1958
			this.mail_changeFolder(inbox,_widget,'');
1959
			this.unlock_tree();
1960
		},this))
1961
			.sendRequest(true);
1962
1963
		return true;
1964
	},
1965
1966
	/**
1967
	 * mail_changeFolder
1968
	 * @param {string} _folder the ID of the selected Node
1969
	 * @param {widget object} _widget handle to the tree widget
1970
	 * @param {string} _previous - Previously selected node ID
1971
	 */
1972
	mail_changeFolder: function(_folder,_widget, _previous) {
1973
1974
		// to reset iframes to the normal status
1975
		this.loadIframe();
1976
1977
		// Abort if user selected an un-selectable node
1978
		// Use image over anything else because...?
1979
		var img = _widget.getSelectedNode().images[0];
1980
		if (img.indexOf('NoSelect') !== -1)
1981
		{
1982
			_widget.reSelectItem(_previous);
1983
			return;
1984
		}
1985
1986
		// Check if this is a top level node and
1987
		// change profile if server has changed
1988
		var server = _folder.split('::');
1989
		var previousServer = _previous.split('::');
1990
		var profile_selected = (_folder.indexOf('::') === -1);
1991
		if (server[0] != previousServer[0] && profile_selected)
1992
		{
1993
			// mail_changeProfile triggers a refresh, no need to do any more
1994
			return this.mail_changeProfile(_folder,_widget, _widget.getSelectedNode().childsCount == 0);
1995
		}
1996
1997
		// Apply new selected folder to list, which updates data
1998
		var nm = _widget.getRoot().getWidgetById(this.nm_index);
1999
		if(nm)
2000
		{
2001
			this.lock_tree();
2002
			nm.applyFilters({'selectedFolder': _folder});
2003
		}
2004
2005
		// Get nice folder name for message, if selected is not a profile
2006
		if(!profile_selected)
2007
		{
2008
			var displayname = _widget.getSelectedLabel();
2009
			var myMsg = (displayname?displayname:_folder).replace(this._unseen_regexp, '')+' '+this.egw.lang('selected');
2010
			this.egw.message(myMsg);
2011
		}
2012
2013
		// Update non-grid
2014
		this.mail_refreshFolderStatus(_folder,'forced',false,false);
2015
		this.mail_refreshQuotaDisplay(server[0]);
2016
		this.mail_preview();
2017
		if (server[0]!=previousServer[0])
2018
		{
2019
			this.mail_callRefreshVacationNotice(server[0]);
2020
			egw.jsonq('mail.mail_ui.ajax_refreshFilters',[server[0]]);
2021
		}
2022
	},
2023
2024
	/**
2025
	 * mail_checkAllSelected
2026
	 *
2027
	 * @param _action
2028
	 * @param _elems
2029
	 * @param _target
2030
	 * @param _confirm
2031
	 */
2032
	mail_checkAllSelected: function(_action, _elems, _target, _confirm)
2033
	{
2034
		if (typeof _confirm == 'undefined') _confirm = false;
2035
		// we can NOT query global object manager for this.nm_index="nm", as we might not get the one from mail,
2036
		// if other tabs are open, we have to query for obj_manager for "mail" and then it's child with id "nm"
2037
		var obj_manager = egw_getObjectManager(this.appname).getObjectById(this.nm_index);
2038
		var that = this;
2039
		var rvMain = false;
2040
		if ((obj_manager && _elems.length>1 && obj_manager.getAllSelected() && !_action.paste) || _action.id=='readall')
2041
		{
2042
			if (_confirm)
2043
			{
2044
				var buttons = [
2045
					{text: this.egw.lang("Yes"), id: "all", "class": "ui-priority-primary", "default": true, image: 'check'},
2046
					{text: this.egw.lang("Cancel"), id:"cancel"}
2047
				];
2048
				var messageToDisplay = '';
2049
				var actionlabel =_action.id;
2050
				switch (_action.id)
2051
				{
2052
					case "readall":
2053
						messageToDisplay = this.egw.lang("Do you really want to mark ALL messages as read in the current folder?")+" ";
2054
						break;
2055
					case "unlabel":
2056
						messageToDisplay = this.egw.lang("Do you really want to remove ALL labels from ALL messages in the current folder?")+" ";
2057
						break;
2058
					case "label1":
2059
						if (_action.id=="label1") actionlabel="important";
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
2060
					case "label2":
2061
						if (_action.id=="label2") actionlabel="job";
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
2062
					case "label3":
2063
						if (_action.id=="label3") actionlabel="personal";
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
2064
					case "label4":
2065
						if (_action.id=="label4") actionlabel="to do";
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
2066
					case "label5":
2067
						if (_action.id=="label5") actionlabel="later";
2068
					case "flagged":
2069
					case "read":
2070
					case "undelete":
2071
						messageToDisplay = this.egw.lang("Do you really want to toggle flag %1 for ALL messages in the current view?",this.egw.lang(actionlabel))+" ";
2072
						if (_action.id.substr(0,5)=='label') messageToDisplay = this.egw.lang("Do you really want to toggle label %1 for ALL messages in the current view?",this.egw.lang(actionlabel))+" ";
2073
						break;
2074
					default:
2075
						var type = null;
2076
						if (_action.id.substr(0,4)=='move' || _action.id === "drop_move_mail")
2077
						{
2078
							type = 'Move';
2079
						}
2080
						if (_action.id.substr(0,4)=='copy' || _action.id === "drop_copy_mail")
2081
						{
2082
							type = 'Copy';
2083
						}
2084
						messageToDisplay = this.egw.lang("Do you really want to apply %1 to ALL messages in the current view?",this.egw.lang(type?type:_action.id))+" ";
2085
				}
2086
				return et2_dialog.show_dialog(function(_button_id) {
2087
					var rv = false;
2088
					switch (_button_id)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
2089
					{
2090
						case "all":
2091
							rv = true;
2092
							break;
2093
						case "cancel":
2094
							rv = 'cancel';
2095
					}
2096
					if (rv !="cancel") that.lock_tree();
2097
					switch (_action.id)
2098
					{
2099
						case "delete":
2100
							that.mail_callDelete(_action, _elems,rv);
2101
							break;
2102
						case "readall":
2103
						case "unlabel":
2104
						case "label1":
2105
						case "label2":
2106
						case "label3":
2107
						case "label4":
2108
						case "label5":
2109
						case "flagged":
2110
						case "read":
2111
						case "undelete":
2112
							that.mail_callFlagMessages(_action, _elems,rv);
2113
							break;
2114
						case "drop_move_mail":
2115
							that.mail_callMove(_action, _elems,_target, rv);
2116
							break;
2117
						case "drop_copy_mail":
2118
							that.mail_callCopy(_action, _elems,_target, rv);
2119
							break;
2120
						default:
2121
							if (_action.id.substr(0,4)=='move') that.mail_callMove(_action, _elems,_target, rv);
2122
							if (_action.id.substr(0,4)=='copy') that.mail_callCopy(_action, _elems,_target, rv);
2123
					}
2124
				},
2125
				messageToDisplay,
2126
				this.egw.lang("Confirm"),
2127
				_action.id, buttons);
2128
			}
2129
			else
2130
			{
2131
				rvMain = true;
2132
			}
2133
		}
2134
		switch (_action.id)
2135
		{
2136
			case "delete":
2137
				this.mail_callDelete(_action, _elems,rvMain);
2138
				break;
2139
			case "unlabel":
2140
			case "label1":
2141
			case "label2":
2142
			case "label3":
2143
			case "label4":
2144
			case "label5":
2145
			case "flagged":
2146
			case "read":
2147
			case "undelete":
2148
				this.mail_callFlagMessages(_action, _elems,rvMain);
2149
				break;
2150
			case "drop_move_mail":
2151
				this.mail_callMove(_action, _elems,_target, rvMain);
2152
				break;
2153
			case "drop_copy_mail":
2154
				this.mail_callCopy(_action, _elems,_target, rvMain);
2155
				break;
2156
			default:
2157
				if (_action.id.substr(0,4)=='move') this.mail_callMove(_action, _elems,_target, rvMain);
2158
				if (_action.id.substr(0,4)=='copy') this.mail_callCopy(_action, _elems,_target, rvMain);
2159
		}
2160
	},
2161
2162
	/**
2163
	 * mail_doActionCall
2164
	 *
2165
	 * @param _action
2166
	 * @param _elems
2167
	 */
2168
	mail_doActionCall: function(_action, _elems)
2169
	{
2170
	},
2171
2172
	/**
2173
	 * mail_getActiveFilters
2174
	 *
2175
	 * @param _action
2176
	 * @return mixed boolean/activeFilters object
2177
	 */
2178
	mail_getActiveFilters: function(_action)
2179
	{
2180
		// we can NOT query global object manager for this.nm_index="nm", as we might not get the one from mail,
2181
		// if other tabs are open, we have to query for obj_manager for "mail" and then it's child with id "nm"
2182
		var obj_manager = egw_getObjectManager(this.appname).getObjectById(this.nm_index);
2183
		if (obj_manager && obj_manager.manager && obj_manager.manager.data && obj_manager.manager.data.nextmatch && obj_manager.manager.data.nextmatch.activeFilters)
2184
		{
2185
			var af = obj_manager.manager.data.nextmatch.activeFilters;
2186
			// merge startdate and enddate into the active filters (if set)
2187
			if (this.et2.getWidgetById('startdate') && this.et2.getWidgetById('startdate').get_value()) af["startdate"] = this.et2.getWidgetById('startdate').date;
2188
			if (this.et2.getWidgetById('enddate') && this.et2.getWidgetById('enddate').get_value()) af["enddate"] = this.et2.getWidgetById('enddate').date;
2189
			return af;
2190
		}
2191
		return false;
2192
	},
2193
2194
	/**
2195
	 * Flag mail as 'read', 'unread', 'flagged' or 'unflagged'
2196
	 *
2197
	 * @param _action _action.id is 'read', 'unread', 'flagged' or 'unflagged'
2198
	 * @param _elems
2199
	 */
2200
	mail_flag: function(_action, _elems)
2201
	{
2202
		this.mail_checkAllSelected(_action,_elems,null,true);
2203
	},
2204
2205
	/**
2206
	 * Flag mail as 'read', 'unread', 'flagged' or 'unflagged'
2207
	 *
2208
	 * @param _action _action.id is 'read', 'unread', 'flagged' or 'unflagged'
2209
	 * @param _elems
2210
	 * @param _allMessagesChecked
2211
	 */
2212
	mail_callFlagMessages: function(_action, _elems, _allMessagesChecked)
2213
	{
2214
		/**
2215
		 * vars
2216
		 */
2217
		var folder = '',
2218
			tree = {},
2219
			formData = {},
2220
			data = {
2221
				msg: [this.et2.getArrayMgr("content").getEntry('mail_id')] || '',
2222
				all: _allMessagesChecked || false,
2223
				popup: typeof this.et2_view!='undefined' || egw(window).is_popup() || false,
2224
				activeFilters: _action.id == 'readall'? false : this.mail_getActiveFilters(_action)
2225
			},
2226
			rowClass = _action.id;
2227
2228
		if (typeof _elems === 'undefined' || _elems.length == 0)
2229
		{
2230
			if (this.mail_isMainWindow && this.mail_currentlyFocussed)
2231
			{
2232
				data.msg = [this.mail_currentlyFocussed];
2233
				_elems = data;
2234
				data.msg = this.mail_getFormData(_elems).msg;
2235
			}
2236
		}
2237
		else // action called by contextmenu
2238
		{
2239
			data.msg = this.mail_getFormData(_elems).msg;
2240
		}
2241
		switch (_action.id)
2242
		{
2243
			case 'read':
2244
				rowClass = 'seen';
2245
				if (data.popup)
2246
				{
2247
					var et_2 = typeof this.et2_view!='undefined'? etemplate2:opener.etemplate2;
2248
					tree = et_2.getByApplication('mail')[0].widgetContainer.getWidgetById(this.nm_index+'[foldertree]');
2249
				}
2250
				else
2251
				{
2252
					tree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
2253
				}
2254
				folder = tree.getSelectedNode().id;
2255
				break;
2256
			case 'readall':
2257
				rowClass = 'seen';
2258
				break;
2259
			case 'label1':
2260
				rowClass = 'labelone';
2261
				break;
2262
			case 'label2':
2263
				rowClass = 'labeltwo';
2264
				break;
2265
			case 'label3':
2266
				rowClass = 'labelthree';
2267
				break;
2268
			case 'label4':
2269
				rowClass = 'labelfour';
2270
				break;
2271
			case 'label5':
2272
				rowClass = 'labelfive';
2273
				break;
2274
			default:
2275
				break;
2276
		}
2277
		jQuery(data).extend({},data, formData);
2278
		if (data['all']=='cancel') return false;
2279
2280
		if (_action.id.substring(0,2)=='un') {
2281
			//old style, only available for undelete and unlabel (no toggle)
2282
			if ( _action.id=='unlabel') // this means all labels should be removed
2283
			{
2284
				var labels = ['labelone','labeltwo','labelthree','labelfour','labelfive'];
2285
				for (var i=0; i<labels.length; i++)	this.mail_removeRowClass(_elems,labels[i]);
2286
				this.mail_flagMessages(_action.id,data);
2287
			}
2288
			else
2289
			{
2290
				this.mail_removeRowClass(_elems,_action.id.substring(2));
2291
				this.mail_setRowClass(_elems,_action.id);
2292
				this.mail_flagMessages(_action.id,data);
2293
			}
2294
		}
2295
		else if (_action.id=='readall')
2296
		{
2297
			this.mail_flagMessages('read',data);
2298
		}
2299
		else
2300
		{
2301
			var msg_set = {msg:[]};
2302
			var msg_unset = {msg:[]};
2303
			var dataElem;
2304
			var flags;
2305
			var classes = '';
2306
			for (var i=0; i<data.msg.length; i++)
2307
			{
2308
				dataElem = egw.dataGetUIDdata(data.msg[i]);
2309
				if(typeof dataElem.data.flags == 'undefined')
2310
				{
2311
					dataElem.data.flags = {};
2312
				}
2313
				flags = dataElem.data.flags;
2314
				classes = dataElem.data['class'] || "";
2315
				classes = classes.split(' ');
2316
				// since we toggle we need to unset the ones already set, and set the ones not set
2317
				// flags is data, UI is done by class, so update both
2318
				// Flags are there or not, class names are flag or 'un'+flag
2319
				if(classes.indexOf(rowClass) >= 0)
2320
				{
2321
					classes.splice(classes.indexOf(rowClass),1);
2322
				}
2323
				if(classes.indexOf('un' + rowClass) >= 0)
2324
				{
2325
					classes.splice(classes.indexOf('un' + rowClass),1);
2326
				}
2327
				if (flags[_action.id])
2328
				{
2329
					msg_unset['msg'].push(data.msg[i]);
2330
					classes.push('un'+rowClass);
2331
					delete flags[_action.id];
2332
				}
2333
				else
2334
				{
2335
					msg_set['msg'].push(data.msg[i]);
2336
					flags[_action.id] = _action.id;
2337
					classes.push(rowClass);
2338
				}
2339
2340
				// Update cache & call callbacks - updates list
2341
				dataElem.data['class']  = classes.join(' ');
2342
				egw.dataStoreUID(data.msg[i],dataElem.data);
2343
2344
				//Refresh the nm rows after we told dataComponent about all changes, since the dataComponent doesn't talk to nm, we need to do it manually
2345
				this.updateFilter_data(data.msg[i], _action.id, data.activeFilters);
2346
			}
2347
2348
			// Notify server of changes
2349
			if (msg_unset['msg'] && msg_unset['msg'].length)
2350
			{
2351
				if (!data['all']) this.mail_flagMessages('un'+_action.id,msg_unset);
2352
			}
2353
			if (msg_set['msg'] && msg_set['msg'].length)
2354
			{
2355
				if (!data['all']) this.mail_flagMessages(_action.id,msg_set);
2356
			}
2357
			//server must do the toggle, as we apply to ALL, not only the visible
2358
			if (data['all']) this.mail_flagMessages(_action.id,data);
2359
			// No further update needed, only in case of read, the counters should be refreshed
2360
			if (_action.id=='read') this.mail_refreshFolderStatus(folder,'thisfolderonly',false,true);
2361
			return;
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
2362
		}
2363
	},
2364
2365
	/**
2366
	 * Update changes on filtered mail rows in nm, triggers manual refresh
2367
	 *
2368
	 * @param {type} _uid mail uid
2369
	 * @param {type} _actionId action id sended by nm action
2370
	 * @param {type} _filters activefilters
2371
	 */
2372
	updateFilter_data: function (_uid, _actionId, _filters)
2373
	{
2374
		var uid = _uid.replace('mail::','');
2375
		var action = '';
2376
		switch (_actionId)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
2377
		{
2378
			case 'flagged':
2379
				action = 'flagged';
2380
				break;
2381
			case 'read':
2382
				if (_filters.filter == 'seen')
2383
				{
2384
					action = 'seen';
2385
				}
2386
				else if (_filters.filter == 'unseen')
2387
				{
2388
					action = 'unseen';
2389
				}
2390
				break;
2391
			case 'label1':
2392
				action = 'keyword1';
2393
				break;
2394
			case 'label2':
2395
				action = 'keyword2';
2396
				break;
2397
			case 'label3':
2398
				action = 'keyword3';
2399
				break;
2400
			case 'label4':
2401
				action = 'keyword4';
2402
				break;
2403
			case 'label4':
2404
				action = 'keyword4';
2405
				break;
2406
		}
2407
		if (action == _filters.filter)
2408
		{
2409
			egw.refresh('','mail',uid, 'delete');
2410
		}
2411
	},
2412
2413
	/**
2414
	 * Flag mail as 'read', 'unread', 'flagged' or 'unflagged'
2415
	 *
2416
	 * @param {object} _flag
2417
	 * @param {object} _elems
2418
	 * @param {boolean} _isPopup
2419
	 */
2420
	mail_flagMessages: function(_flag, _elems,_isPopup)
2421
	{
2422
		egw.jsonq('mail.mail_ui.ajax_flagMessages',[_flag, _elems]);
2423
		//	.sendRequest(true);
2424
	},
2425
2426
	/**
2427
	 * display header lines, or source of mail, depending on the url given
2428
	 *
2429
	 * @param _url
2430
	 */
2431
	mail_displayHeaderLines: function(_url) {
2432
		// only used by right clickaction
2433
		egw_openWindowCentered(_url,'mail_display_headerLines','870','600',window.outerWidth/2,window.outerHeight/2);
2434
	},
2435
2436
	/**
2437
	 * View header of a message
2438
	 *
2439
	 * @param _action
2440
	 * @param _elems _elems[0].id is the row-id
2441
	 */
2442
	mail_header: function(_action, _elems)
2443
	{
2444
		if (typeof _elems == 'undefined'|| _elems.length==0)
2445
		{
2446
			if (this.et2.getArrayMgr("content").getEntry('mail_id'))
2447
			{
2448
				var _elems = [];
2449
				_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
2450
			}
2451
			if ((typeof _elems == 'undefined' || _elems.length==0) && this.mail_isMainWindow)
2452
			{
2453
				if (this.mail_currentlyFocussed)
2454
				{
2455
					var _elems = [];
2456
					_elems.push({id:this.mail_currentlyFocussed});
2457
				}
2458
			}
2459
		}
2460
		//alert('mail_header('+_elems[0].id+')');
2461
		var url = window.egw_webserverUrl+'/index.php?';
2462
		url += 'menuaction=mail.mail_ui.displayHeader';	// todo compose for Draft folder
2463
		url += '&id='+_elems[0].id;
2464
		this.mail_displayHeaderLines(url);
2465
	},
2466
2467
	/**
2468
	 * View message source
2469
	 *
2470
	 * @param _action
2471
	 * @param _elems _elems[0].id is the row-id
2472
	 */
2473
	mail_mailsource: function(_action, _elems)
2474
	{
2475
		if (typeof _elems == 'undefined' || _elems.length==0)
2476
		{
2477
			if (this.et2.getArrayMgr("content").getEntry('mail_id'))
2478
			{
2479
				var _elems = [];
2480
				_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
2481
			}
2482
			if ((typeof _elems == 'undefined'|| _elems.length==0) && this.mail_isMainWindow)
2483
			{
2484
				if (this.mail_currentlyFocussed)
2485
				{
2486
					var _elems = [];
2487
					_elems.push({id:this.mail_currentlyFocussed});
2488
				}
2489
			}
2490
		}
2491
		//alert('mail_mailsource('+_elems[0].id+')');
2492
		var url = window.egw_webserverUrl+'/index.php?';
2493
		url += 'menuaction=mail.mail_ui.saveMessage';	// todo compose for Draft folder
2494
		url += '&id='+_elems[0].id;
2495
		url += '&location=display';
2496
		this.mail_displayHeaderLines(url);
2497
	},
2498
2499
	/**
2500
	 * Save a message
2501
	 *
2502
	 * @param _action
2503
	 * @param _elems _elems[0].id is the row-id
2504
	 */
2505
	mail_save: function(_action, _elems)
2506
	{
2507
		if (typeof _elems == 'undefined' || _elems.length==0)
2508
		{
2509
			if (this.et2.getArrayMgr("content").getEntry('mail_id'))
2510
			{
2511
				var _elems = [];
2512
				_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
2513
			}
2514
			if ((typeof _elems == 'undefined' || _elems.length==0) && this.mail_isMainWindow)
2515
			{
2516
				if (this.mail_currentlyFocussed)
2517
				{
2518
					var _elems = [];
2519
					_elems.push({id:this.mail_currentlyFocussed});
2520
				}
2521
			}
2522
		}
2523
		//alert('mail_save('+_elems[0].id+')');
2524
		var url = window.egw_webserverUrl+'/index.php?';
2525
		url += 'menuaction=mail.mail_ui.saveMessage';	// todo compose for Draft folder
2526
		url += '&id='+_elems[0].id;
2527
		//window.open(url,'_blank','dependent=yes,width=100,height=100,scrollbars=yes,status=yes');
2528
		this.et2._inst.download(url);
2529
	},
2530
2531
	/**
2532
	 * User clicked an address (FROM, TO, etc)
2533
	 *
2534
	 * @param {object} tag_info with values for attributes id, label, title, ...
2535
	 * @param {widget object} widget
2536
	 *
2537
	 * @todo seems this function is not implemented, need to be checked if it is neccessary at all
2538
	 */
2539
	address_click: function(tag_info, widget)
2540
	{
2541
2542
	},
2543
2544
	/**
2545
	 * displayAttachment
2546
	 *
2547
	 * @param {object} tag_info
2548
	 * @param {widget object} widget
2549
	 * @param {object} calledForCompose
2550
	 */
2551
	displayAttachment: function(tag_info, widget, calledForCompose)
2552
	{
2553
		var mailid;
2554
		var attgrid;
2555
		if (typeof calledForCompose == 'undefined' || typeof calledForCompose == 'object') calledForCompose=false;
2556
		if (calledForCompose===false)
2557
		{
2558
			if (this.mail_isMainWindow)
2559
			{
2560
				mailid = this.mail_currentlyFocussed;//this.et2.getArrayMgr("content").getEntry('mail_id');
2561
				var p = widget.getParent();
2562
				var cont = p.getArrayMgr("content").data;
2563
				attgrid = cont[widget.id.replace(/\[filename\]/,'')];
2564
			}
2565
			else
2566
			{
2567
				mailid = this.et2.getArrayMgr("content").getEntry('mail_id');
2568
				attgrid = this.et2.getArrayMgr("content").getEntry('mail_displayattachments')[widget.id.replace(/\[filename\]/,'')];
2569
			}
2570
		}
2571
		if (calledForCompose===true)
2572
		{
2573
			// CALLED FOR COMPOSE; processedmail_id could hold several IDs seperated by comma
2574
			attgrid = this.et2.getArrayMgr("content").getEntry('attachments')[widget.id.replace(/\[name\]/,'')];
2575
			var mailids = this.et2.getArrayMgr("content").getEntry('processedmail_id');
2576
			var mailida = mailids.split(',');
2577
			// either several attachments of one email, or multiple emlfiles
2578
			mailid = mailida.length==1 ? mailida[0] : mailida[widget.id.replace(/\[name\]/,'')];
2579
			if (typeof attgrid.uid != 'undefined' && attgrid.uid && mailid.indexOf(attgrid.uid)==-1)
2580
			{
2581
				for (var i=0; i<mailida.length; i++)
2582
				{
2583
					if (mailida[i].indexOf('::'+attgrid.uid)>-1) mailid = mailida[i];
2584
				}
2585
			}
2586
		}
2587
		var url = window.egw_webserverUrl+'/index.php?';
2588
		var width;
2589
		var height;
2590
		var windowName ='mail';
2591
		switch(attgrid.type.toUpperCase())
0 ignored issues
show
Bug introduced by
The variable attgrid does not seem to be initialized in case calledForCompose === false on line 2556 is false. Are you sure this can never be the case?
Loading history...
2592
		{
2593
			case 'MESSAGE/RFC822':
2594
				url += 'menuaction=mail.mail_ui.displayMessage';	// todo compose for Draft folder
2595
				url += '&mode=display';//message/rfc822 attachments should be opened in display mode
2596
				url += '&id='+mailid;
0 ignored issues
show
Bug introduced by
The variable mailid does not seem to be initialized in case calledForCompose === false on line 2556 is false. Are you sure this can never be the case?
Loading history...
2597
				url += '&part='+attgrid.partID;
2598
				url += '&is_winmail='+attgrid.winmailFlag;
2599
				windowName = windowName+'displayMessage_'+mailid+'_'+attgrid.partID;
2600
				width = 870;
2601
				height = egw_getWindowOuterHeight();
2602
				break;
2603
			case 'IMAGE/JPEG':
2604
			case 'IMAGE/PNG':
2605
			case 'IMAGE/GIF':
2606
			case 'IMAGE/BMP':
2607
			case 'APPLICATION/PDF':
2608
			case 'TEXT/PLAIN':
2609
			case 'TEXT/HTML':
2610
			case 'TEXT/DIRECTORY':
2611
/*
2612
				$sfxMimeType = $value['mimeType'];
2613
				$buff = explode('.',$value['name']);
2614
				$suffix = '';
2615
				if (is_array($buff)) $suffix = array_pop($buff); // take the last extension to check with ext2mime
2616
				if (!empty($suffix)) $sfxMimeType = mime_magic::ext2mime($suffix);
2617
				if (strtoupper($sfxMimeType) == 'TEXT/VCARD' || strtoupper($sfxMimeType) == 'TEXT/X-VCARD')
2618
				{
2619
					$attachments[$key]['mimeType'] = $sfxMimeType;
2620
					$value['mimeType'] = strtoupper($sfxMimeType);
2621
				}
2622
*/
2623
			case 'TEXT/X-VCARD':
2624
			case 'TEXT/VCARD':
2625
			case 'TEXT/CALENDAR':
2626
			case 'TEXT/X-VCALENDAR':
2627
				url += 'menuaction=mail.mail_ui.getAttachment';	// todo compose for Draft folder
2628
				url += '&id='+mailid;
2629
				url += '&part='+attgrid.partID;
2630
				url += '&is_winmail='+attgrid.winmailFlag;
2631
				windowName = windowName+'displayAttachment_'+mailid+'_'+attgrid.partID;
2632
				var reg = '800x600';
2633
				var reg2;
2634
				// handle calendar/vcard
2635
				if (attgrid.type.toUpperCase()=='TEXT/CALENDAR')
2636
				{
2637
					windowName = 'maildisplayEvent_'+mailid+'_'+attgrid.partID;
2638
					reg2 = egw.link_get_registry('calendar');
2639
					if (typeof reg2['view'] != 'undefined' && typeof reg2['view_popup'] != 'undefined' )
2640
					{
2641
						reg = reg2['view_popup'];
2642
					}
2643
				}
2644
				if (attgrid.type.toUpperCase()=='TEXT/X-VCARD' || attgrid.type.toUpperCase()=='TEXT/VCARD')
2645
				{
2646
					windowName = 'maildisplayContact_'+mailid+'_'+attgrid.partID;
2647
					reg2 = egw.link_get_registry('addressbook');
2648
					if (typeof reg2['add'] != 'undefined' && typeof reg2['add_popup'] != 'undefined' )
2649
					{
2650
						reg = reg2['add_popup'];
2651
					}
2652
				}
2653
				var w_h =reg.split('x');
2654
				width = w_h[0];
2655
				height = w_h[1];
2656
				break;
2657
			default:
2658
				url += 'menuaction=mail.mail_ui.getAttachment';	// todo compose for Draft folder
2659
				url += '&id='+mailid;
2660
				url += '&part='+attgrid.partID;
2661
				url += '&is_winmail='+attgrid.winmailFlag;
2662
				windowName = windowName+'displayAttachment_'+mailid+'_'+attgrid.partID;
2663
				width = 870;
2664
				height = 600;
2665
				break;
2666
		}
2667
		egw_openWindowCentered(url,windowName,width,height);
2668
	},
2669
2670
	/**
2671
	 * displayUploadedFile
2672
	 *
2673
	 * @param {object} tag_info
2674
	 * @param {widget object} widget
2675
	 */
2676
	displayUploadedFile: function(tag_info, widget)
2677
	{
2678
		var attgrid;
2679
		attgrid = this.et2.getArrayMgr("content").getEntry('attachments')[widget.id.replace(/\[name\]/,'')];
2680
2681
		if (attgrid.uid && (attgrid.partID||attgrid.folder))
2682
		{
2683
			this.displayAttachment(tag_info, widget, true);
2684
			return;
2685
		}
2686
		var get_param = {
2687
			menuaction: 'mail.mail_compose.getAttachment',	// todo compose for Draft folder
2688
			tmpname: attgrid.tmp_name,
2689
			etemplate_exec_id: this.et2._inst.etemplate_exec_id
2690
		};
2691
		var width;
2692
		var height;
2693
		var windowName ='maildisplayAttachment_'+attgrid.file.replace(/\//g,"_");
2694
		switch(attgrid.type.toUpperCase())
2695
		{
2696
			case 'IMAGE/JPEG':
2697
			case 'IMAGE/PNG':
2698
			case 'IMAGE/GIF':
2699
			case 'IMAGE/BMP':
2700
			case 'APPLICATION/PDF':
2701
			case 'TEXT/PLAIN':
2702
			case 'TEXT/HTML':
2703
			case 'TEXT/DIRECTORY':
2704
			case 'TEXT/X-VCARD':
2705
			case 'TEXT/VCARD':
2706
			case 'TEXT/CALENDAR':
2707
			case 'TEXT/X-VCALENDAR':
2708
				var reg = '800x600';
2709
				var reg2;
2710
				// handle calendar/vcard
2711
				if (attgrid.type.toUpperCase()=='TEXT/CALENDAR')
2712
				{
2713
					windowName = 'maildisplayEvent_'+attgrid.file.replace(/\//g,"_");
2714
					reg2 = egw.link_get_registry('calendar');
2715
					if (typeof reg2['view'] != 'undefined' && typeof reg2['view_popup'] != 'undefined' )
2716
					{
2717
						reg = reg2['view_popup'];
2718
					}
2719
				}
2720
				if (attgrid.type.toUpperCase()=='TEXT/X-VCARD' || attgrid.type.toUpperCase()=='TEXT/VCARD')
2721
				{
2722
					windowName = 'maildisplayContact_'+attgrid.file.replace(/\//g,"_");
2723
					reg2 = egw.link_get_registry('addressbook');
2724
					if (typeof reg2['add'] != 'undefined' && typeof reg2['add_popup'] != 'undefined' )
2725
					{
2726
						reg = reg2['add_popup'];
2727
					}
2728
				}
2729
				var w_h =reg.split('x');
2730
				width = w_h[0];
2731
				height = w_h[1];
2732
				break;
2733
			case 'MESSAGE/RFC822':
2734
			default:
2735
				get_param.mode = 'save';
2736
				width = 870;
2737
				height = 600;
2738
				break;
2739
		}
2740
		egw.openPopup(egw.link('/index.php', get_param), width, height, windowName);
2741
	},
2742
2743
	saveAttachment: function(tag_info, widget)
2744
	{
2745
		var mailid;
2746
		var attgrid;
2747
		if (this.mail_isMainWindow)
2748
		{
2749
			mailid = this.mail_currentlyFocussed;//this.et2.getArrayMgr("content").getEntry('mail_id');
2750
			var p = widget.getParent();
2751
			var cont = p.getArrayMgr("content").data;
2752
			attgrid = cont[widget.id.replace(/\[save\]/,'')];
2753
		}
2754
		else
2755
		{
2756
			mailid = this.et2.getArrayMgr("content").getEntry('mail_id');
2757
			attgrid = this.et2.getArrayMgr("content").getEntry('mail_displayattachments')[widget.id.replace(/\[save\]/,'')];
2758
		}
2759
		var url = window.egw_webserverUrl+'/index.php?';
2760
		url += 'menuaction=mail.mail_ui.getAttachment';	// todo compose for Draft folder
2761
		url += '&mode=save';
2762
		url += '&id='+mailid;
2763
		url += '&part='+attgrid.partID;
2764
		url += '&is_winmail='+attgrid.winmailFlag;
2765
		this.et2._inst.download(url);
2766
	},
2767
2768
	saveAllAttachmentsToZip: function(tag_info, widget)
2769
	{
2770
		var mailid;
2771
		var attgrid;
2772
		if (this.mail_isMainWindow)
2773
		{
2774
			mailid = this.mail_currentlyFocussed;//this.et2.getArrayMgr("content").getEntry('mail_id');
2775
			var p = widget.getParent();
2776
			var cont = p.getArrayMgr("content").data;
2777
			attgrid = cont[widget.id.replace(/\[save\]/,'')];
2778
		}
2779
		else
2780
		{
2781
			mailid = this.et2.getArrayMgr("content").getEntry('mail_id');
2782
			attgrid = this.et2.getArrayMgr("content").getEntry('mail_displayattachments')[widget.id.replace(/\[save\]/,'')];
2783
		}
2784
		var url = window.egw_webserverUrl+'/index.php?';
2785
		url += 'menuaction=mail.mail_ui.download_zip';	// todo compose for Draft folder
2786
		url += '&mode=save';
2787
		url += '&id='+mailid;
2788
		this.et2._inst.download(url);
2789
	},
2790
2791
	saveAttachmentToVFS: function(tag_info, widget)
2792
	{
2793
		var mailid;
2794
		var attgrid;
2795
		if (this.mail_isMainWindow)
2796
		{
2797
			mailid = this.mail_currentlyFocussed;//this.et2.getArrayMgr("content").getEntry('mail_id');
2798
			var p = widget.getParent();
2799
			var cont = p.getArrayMgr("content").data;
2800
			attgrid = cont[widget.id.replace(/\[saveAsVFS\]/,'')];
2801
		}
2802
		else
2803
		{
2804
			mailid = this.et2.getArrayMgr("content").getEntry('mail_id');
2805
			attgrid = this.et2.getArrayMgr("content").getEntry('mail_displayattachments')[widget.id.replace(/\[saveAsVFS\]/,'')];
2806
		}
2807
		var url = window.egw_webserverUrl+'/index.php?';
2808
		var width=640;
2809
		var height=570;
2810
		var windowName ='mail';
2811
		url += 'menuaction=filemanager.filemanager_select.select';	// todo compose for Draft folder
2812
		url += '&mode=saveas';
2813
		url += '&id='+mailid+'::'+attgrid.partID+'::'+attgrid.winmailFlag;
2814
		url += '&name='+attgrid.filename;
2815
		url += '&type='+attgrid.type.toLowerCase();
2816
		url += '&method=mail.mail_ui.vfsSaveAttachment';
2817
		url += '&label='+egw.lang('Save');
2818
		egw_openWindowCentered(url,windowName,width,height);
2819
	},
2820
2821
	saveAllAttachmentsToVFS: function(tag_info, widget)
2822
	{
2823
		var mailid;
2824
		var attgrid;
2825
		if (this.mail_isMainWindow)
2826
		{
2827
			mailid = this.mail_currentlyFocussed;//this.et2.getArrayMgr("content").getEntry('mail_id');
2828
			var p = widget.getParent();
2829
			attgrid = p.getArrayMgr("content").data;
2830
		}
2831
		else
2832
		{
2833
			mailid = this.et2.getArrayMgr("content").getEntry('mail_id');
2834
			attgrid = this.et2.getArrayMgr("content").getEntry('mail_displayattachments');
2835
		}
2836
		var url = window.egw_webserverUrl+'/index.php?';
2837
		var width=640;
2838
		var height=570;
2839
		var windowName ='mail';
2840
		url += 'menuaction=filemanager.filemanager_select.select';	// todo compose for Draft folder
2841
		url += '&mode=select-dir';
2842
		url += '&method=mail.mail_ui.vfsSaveAttachment';
2843
		url += '&label='+egw.lang('Save all');
2844
		for (var i=0;i<attgrid.length;i++)
2845
		{
2846
			if (attgrid[i] != null) url += '&id['+i+']='+mailid+'::'+attgrid[i].partID+'::'+attgrid[i].winmailFlag+'::'+attgrid[i].filename;
2847
		}
2848
		egw_openWindowCentered(url,windowName,width,height);
2849
	},
2850
2851
	/**
2852
	 * Save a message to filemanager
2853
	 *
2854
	 * @param _action
2855
	 * @param _elems _elems[0].id is the row-id
2856
	 */
2857
	mail_save2fm: function(_action, _elems)
2858
	{
2859
		if (typeof _elems == 'undefined' || _elems.length==0)
2860
		{
2861
			if (this.et2.getArrayMgr("content").getEntry('mail_id'))
2862
			{
2863
				var _elems = [];
2864
				_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
2865
			}
2866
			if ((typeof _elems == 'undefined' || _elems.length==0) && this.mail_isMainWindow)
2867
			{
2868
				if (this.mail_currentlyFocussed)
2869
				{
2870
					var _elems = [];
2871
					_elems.push({id:this.mail_currentlyFocussed});
2872
				}
2873
			}
2874
		}
2875
		var _id = _elems[0].id;
2876
		var dataElem = egw.dataGetUIDdata(_id);
2877
		var url = window.egw_webserverUrl+'/index.php?';
2878
		url += 'menuaction=filemanager.filemanager_select.select';	// todo compose for Draft folder
2879
		url += '&mode=saveas';
2880
		var subject = dataElem? dataElem.data.subject: _elems[0].subject;
2881
		var filename = subject.replace(/[\f\n\t\v]/g,"_")|| 'unknown';
2882
		url += '&name='+encodeURIComponent(filename+'.eml');
2883
		url += '&mime=message'+encodeURIComponent('/')+'rfc822';
2884
		url += '&method=mail.mail_ui.vfsSaveMessage';
2885
		url += '&id='+_elems[0].id;
2886
		url += '&label=Save';
2887
		egw_openWindowCentered(url,'vfs_save_message_'+_elems[0].id,'680','400',window.outerWidth/2,window.outerHeight/2);
2888
2889
	},
2890
2891
	/**
2892
	 * Integrate mail message into another app's entry
2893
	 *
2894
	 * @param _action
2895
	 * @param _elems _elems[0].id is the row-id
2896
	 */
2897
	mail_integrate: function(_action, _elems)
2898
	{
2899
		var app = _action.id;
2900
		var w_h = ['750','580']; // define a default wxh if there's no popup size registered
2901
2902
		if (typeof _action.data != 'undefined' )
2903
		{
2904
			if (typeof _action.data.popup != 'undefined' && _action.data.popup) w_h = _action.data.popup.split('x');
2905
			if (typeof _action.data.mail_import != 'undefined') var mail_import_hook = _action.data.mail_import;
2906
		}
2907
2908
		if (typeof _elems == 'undefined' || _elems.length==0)
2909
		{
2910
			if (this.et2.getArrayMgr("content").getEntry('mail_id'))
2911
			{
2912
				var _elems = [];
2913
				_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
2914
			}
2915
			if ((typeof _elems == 'undefined' || _elems.length==0) && this.mail_isMainWindow)
2916
			{
2917
				if (this.mail_currentlyFocussed)
2918
				{
2919
					var _elems = [];
2920
					_elems.push({id:this.mail_currentlyFocussed});
2921
				}
2922
			}
2923
		}
2924
2925
		var url = window.egw_webserverUrl+ '/index.php?menuaction=mail.mail_integration.integrate&rowid=' + _elems[0].id + '&app='+app;
2926
2927
		if (mail_import_hook && typeof mail_import_hook.app_entry_method != 'undefined')
2928
		{
2929
			var data = egw.dataGetUIDdata(_elems[0].id);
2930
			var subject = (data && typeof data.data != 'undefined')? data.data.subject : '';
2931
			this.integrate_checkAppEntry('Select '+ app + ' entry', app, subject, url,  mail_import_hook.app_entry_method, function (args){
2932
				egw_openWindowCentered(args.url+ (args.entryid ?'&entry_id=' + args.entryid: ''),'import_mail_'+_elems[0].id,w_h[0],w_h[1]);
2933
			});
2934
		}
2935
		else
2936
		{
2937
			egw_openWindowCentered(url,'import_mail_'+_elems[0].id,w_h[0],w_h[1]);
2938
		}
2939
2940
	},
2941
2942
   /**
2943
	* Checks the application entry existance and offers user
2944
	* to select desire app id to append mail content into it,
2945
	* or add the mail content as a new app entry
2946
	*
2947
	* @param {string} _title select app entry title
2948
	* @param {string} _appName app to be integrated
2949
	* @param {string} _subject
2950
	* @param {string} _url
2951
	* @param {string} _appCheckCallback registered mail_import hook method
2952
	* @param {function} _execCallback function to get called on dialog actions
2953
	*/
2954
	integrate_checkAppEntry: function (_title, _appName, _subject ,_url, _appCheckCallback, _execCallback)
2955
	{
2956
	   var subject = _subject || '';
2957
	   var execCallback = _execCallback;
2958
	   egw.json(_appCheckCallback, subject,function(_entryId){
2959
2960
		   // if there's no entry saved already
2961
		   // open dialog in order to select one
2962
		   if (!_entryId)
2963
		   {
2964
			   var buttons = [
2965
				   {text: 'Append', id: 'append', image: 'check', default:true},
2966
				   {text: 'Add as new', id: 'new', image: 'check'},
2967
				   {text: 'Cancel', id: 'cancel', image: 'check'}
2968
			   ];
2969
			   et2_createWidget("dialog",
2970
			   {
2971
				   callback: function(_buttons, _value)
2972
				   {
2973
					   if (_buttons == 'cancel') return;
2974
					   if (_buttons == 'append' && _value)
2975
					   {
2976
						   _entryId = _value.id;
2977
					   }
2978
					   execCallback.call(this,{entryid:_entryId,url:_url});
2979
				   },
2980
				   title: egw.lang(_title),
2981
				   buttons: buttons||et2_dialog.BUTTONS_OK_CANCEL,
2982
				   value:{
2983
					   content:{
2984
						   appName:_appName // appName to search on its list later
2985
				   }},
2986
				   template: egw.webserverUrl+'/mail/templates/default/integration_to_entry_dialog.xet'
2987
			   },et2_dialog._create_parent('mail'));
2988
		   }
2989
		   else // there is an entry saved related to this mail's subject
2990
		   {
2991
			   execCallback.call(this,{entryid:_entryId,url:_url});
2992
		   }
2993
	   },this,true,this).sendRequest();
2994
	},
2995
2996
	/**
2997
	 * mail_getFormData
2998
	 *
2999
	 * @param {object} _actionObjects the senders
3000
	 *
3001
	 * @return structured array of message ids: array(msg=>message-ids)
3002
	 */
3003
	mail_getFormData: function(_actionObjects) {
3004
		var messages = {};
3005
		// if
3006
		if (typeof _actionObjects['msg'] != 'undefined' && _actionObjects['msg'].length>0) return _actionObjects;
3007
		if (_actionObjects.length>0)
3008
		{
3009
			messages['msg'] = [];
3010
		}
3011
3012
		for (var i = 0; i < _actionObjects.length; i++)
3013
		{
3014
			if (_actionObjects[i].id.length>0)
3015
			{
3016
				messages['msg'][i] = _actionObjects[i].id;
3017
			}
3018
		}
3019
3020
		return messages;
3021
	},
3022
3023
	/**
3024
	 * mail_setRowClass
3025
	 *
3026
	 * @param {object} _actionObjects the senders
3027
	 * @param {string} _class
3028
	 */
3029
	mail_setRowClass: function(_actionObjects,_class) {
3030
		if (typeof _class == 'undefined') return false;
3031
3032
		if (typeof _actionObjects['msg'] == 'undefined')
3033
		{
3034
			for (var i = 0; i < _actionObjects.length; i++)
3035
			{
3036
				// Check that the ID & interface is there.  Paste is missing iface.
3037
				if (_actionObjects[i].id.length>0 && _actionObjects[i].iface)
3038
				{
3039
					var dataElem = jQuery(_actionObjects[i].iface.getDOMNode());
3040
					dataElem.addClass(_class);
3041
3042
				}
3043
			}
3044
		}
3045
		else
3046
		{
3047
			for (var i = 0; i < _actionObjects['msg'].length; i++)
3048
			{
3049
				var mail_uid = _actionObjects['msg'][i];
3050
3051
				// Get the record from data cache
3052
				var dataElem = egw.dataGetUIDdata(mail_uid);
3053
				if(dataElem == null || typeof dataElem == undefined)
3054
				{
3055
					// Unknown ID, nothing to update
3056
					return;
3057
				}
3058
3059
				// Update class
3060
				dataElem.data['class']  += ' ' + _class;
3061
3062
				// need to update flags too
3063
				switch(_class)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
3064
				{
3065
					case 'unseen':
3066
						delete dataElem.data.flags.read;
3067
						break;
3068
				}
3069
3070
				// Update record, which updates all listeners (including nextmatch)
3071
				egw.dataStoreUID(mail_uid,dataElem.data);
3072
			}
3073
		}
3074
	},
3075
3076
	/**
3077
	 * mail_removeRowFlag
3078
	 * Removes a flag and updates the CSS class.  Updates the UI, but not the server.
3079
	 *
3080
	 * @param {action object} _actionObjects the senders, or a messages object
3081
	 * @param {string} _class the class to be removed
3082
	 */
3083
	mail_removeRowClass: function(_actionObjects,_class) {
3084
		if (typeof _class == 'undefined') return false;
3085
3086
		if (typeof _actionObjects['msg'] == 'undefined')
3087
		{
3088
			for (var i = 0; i < _actionObjects.length; i++)
3089
			{
3090
				if (_actionObjects[i].id.length>0)
3091
				{
3092
					var dataElem = jQuery(_actionObjects[i].iface.getDOMNode());
3093
					dataElem.removeClass(_class);
3094
3095
				}
3096
			}
3097
		}
3098
		else
3099
		{
3100
			for (var i = 0; i < _actionObjects['msg'].length; i++)
3101
			{
3102
				var mail_uid = _actionObjects['msg'][i];
3103
3104
				// Get the record from data cache
3105
				var dataElem = egw.dataGetUIDdata(mail_uid);
3106
				if(dataElem == null || typeof dataElem == undefined)
3107
				{
3108
					// Unknown ID, nothing to update
3109
					return;
3110
				}
3111
3112
				// Update class
3113
				var classes = dataElem.data['class'] || "";
3114
				classes = classes.split(' ');
3115
				if(classes.indexOf(_class) >= 0)
3116
				{
3117
					classes.splice(classes.indexOf(_class),1);
3118
					dataElem.data['class'] = classes.join(' ');
3119
3120
					// need to update flags too
3121
					switch(_class)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
3122
					{
3123
						case 'unseen':
3124
							dataElem.data.flags.read = true;
3125
							break;
3126
					}
3127
3128
					// Update record, which updates all listeners (including nextmatch)
3129
					egw.dataStoreUID(mail_uid,dataElem.data);
3130
				}
3131
			}
3132
		}
3133
	},
3134
3135
	/**
3136
	 * mail_move2folder - implementation of the move action from action menu
3137
	 *
3138
	 * @param _action _action.id holds folder target information
3139
	 * @param _elems - the representation of the elements to be affected
3140
	 */
3141
	mail_move2folder: function(_action, _elems) {
3142
		this.mail_move(_action, _elems, null);
3143
	},
3144
3145
	/**
3146
	 * mail_move - implementation of the move action from drag n drop
3147
	 *
3148
	 * @param _action
3149
	 * @param _senders - the representation of the elements dragged
3150
	 * @param _target - the representation of the target
3151
	 */
3152
	mail_move: function(_action,_senders,_target) {
3153
		this.mail_checkAllSelected(_action,_senders,_target,true);
3154
	},
3155
3156
	/**
3157
	 * mail_move - implementation of the move action from drag n drop
3158
	 *
3159
	 * @param _action
3160
	 * @param _senders - the representation of the elements dragged
3161
	 * @param _target - the representation of the target
3162
	 * @param _allMessagesChecked
3163
	 */
3164
	mail_callMove: function(_action,_senders,_target,_allMessagesChecked) {
3165
		var target = _action.id == 'drop_move_mail' ? _target.iface.id : _action.id.substr(5);
3166
		var messages = this.mail_getFormData(_senders);
3167
		if (typeof _allMessagesChecked=='undefined') _allMessagesChecked=false;
3168
3169
		// Directly delete any cache for target
3170
		if(window.localStorage)
3171
		{
3172
			for(var i = 0; i < window.localStorage.length; i++)
3173
			{
3174
				var key = window.localStorage.key(i);
3175
3176
				// Find directly by what the key would look like
3177
				if(key.indexOf('cached_fetch_mail::{"selectedFolder":"'+target+'"') == 0)
3178
				{
3179
					window.localStorage.removeItem(key);
3180
				}
3181
			}
3182
		}
3183
		// TODO: Write move/copy function which cares about doing the same stuff
3184
		// as the "onNodeSelect" function!
3185
		messages['all'] = _allMessagesChecked;
3186
		if (messages['all']=='cancel') return false;
3187
		if (messages['all']) messages['activeFilters'] = this.mail_getActiveFilters(_action);
3188
3189
		// Make sure a default target folder is set in case of drop target is parent 0 (mail account name)
3190
		if (!target.match(/::/g)) target += '::INBOX';
3191
3192
		var self = this;
3193
		var nm = this.et2.getWidgetById(this.nm_index);
3194
		// thev 4th param indicates if it is a normal move messages action. if not the action is a move2.... (archiveFolder) action
3195
		egw.json('mail.mail_ui.ajax_copyMessages',[target, messages, 'move', (_action.id.substr(0,4)=='move'&&_action.id.substr(4,1)=='2'?'2':'_') ], function(){
3196
			self.unlock_tree();
3197
			// Nextmatch automatically selects the next row and calls preview.
3198
			// Unselect it and thanks to the timeout selectionMgr uses, preview
3199
			// will close when the selection callback fires instead of load the
3200
			// next message
3201
			nm.controller._selectionMgr.resetSelection();
3202
3203
			// Server response may contain refresh, but it's always delete
3204
			// Refresh list if current view is the target (happens when pasting)
3205
			var tree = self.et2.getWidgetById('nm[foldertree]');
3206
			if(nm && tree && target == tree.getValue())
3207
			{
3208
				// Can't trust the sorting, needs to be full refresh
3209
				nm.refresh();
3210
			}
3211
		})
3212
			.sendRequest();
3213
		this.mail_setRowClass(_senders,'deleted');
3214
		// Server response may contain refresh, not needed here
3215
	},
3216
3217
	/**
3218
	 * mail_copy - implementation of the move action from drag n drop
3219
	 *
3220
	 * @param _action
3221
	 * @param _senders - the representation of the elements dragged
3222
	 * @param _target - the representation of the target
3223
	 */
3224
	mail_copy: function(_action,_senders,_target) {
3225
		this.mail_checkAllSelected(_action,_senders,_target,true);
3226
	},
3227
3228
	/**
3229
	 * mail_callCopy - implementation of the copy action from drag n drop
3230
	 *
3231
	 * @param _action
3232
	 * @param _senders - the representation of the elements dragged
3233
	 * @param _target - the representation of the target
3234
	 * @param _allMessagesChecked
3235
	 */
3236
	mail_callCopy: function(_action,_senders,_target,_allMessagesChecked) {
3237
		var target = _action.id == 'drop_copy_mail' ? _target.iface.id : _action.id.substr(5);
3238
		var messages = this.mail_getFormData(_senders);
3239
		if (typeof _allMessagesChecked=='undefined') _allMessagesChecked=false;
3240
		// TODO: Write move/copy function which cares about doing the same stuff
3241
		// as the "onNodeSelect" function!
3242
		messages['all'] = _allMessagesChecked;
3243
		if (messages['all']=='cancel') return false;
3244
		if (messages['all']) messages['activeFilters'] = this.mail_getActiveFilters(_action);
3245
		var self = this;
3246
		egw.json('mail.mail_ui.ajax_copyMessages',[target, messages],function (){self.unlock_tree();})
3247
			.sendRequest();
3248
		// Server response contains refresh
3249
	},
3250
3251
	/**
3252
	 * mail_AddFolder - implementation of the AddFolder action of right click options on the tree
3253
	 *
3254
	 * @param _action
3255
	 * @param _senders - the representation of the tree leaf to be manipulated
3256
	 */
3257
	mail_AddFolder: function(_action,_senders) {
3258
		//action.id == 'add'
3259
		//_senders.iface.id == target leaf / leaf to edit
3260
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
3261
		var OldFolderName = ftree.getLabel(_senders[0].id).replace(this._unseen_regexp,'');
3262
		var buttons = [
3263
			{text: this.egw.lang("Add"), id: "add", "class": "ui-priority-primary", "default": true},
3264
			{text: this.egw.lang("Cancel"), id:"cancel"}
3265
		];
3266
		et2_dialog.show_prompt(function(_button_id, _value) {
3267
			var NewFolderName = null;
3268
			if (_value.length>0) NewFolderName = _value;
3269
			//alert(NewFolderName);
3270
			if (NewFolderName && NewFolderName.length>0)
3271
			{
3272
				switch (_button_id)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
3273
				{
3274
					case "add":
3275
						egw.json('mail.mail_ui.ajax_addFolder',[_senders[0].id, NewFolderName])
3276
							.sendRequest(true);
3277
						return;
3278
					case "cancel":
3279
				}
3280
			}
3281
		},
3282
		this.egw.lang("Enter the name for the new Folder:"),
3283
		this.egw.lang("Add a new Folder to %1:",OldFolderName),
3284
		'', buttons);
3285
	},
3286
3287
	/**
3288
	 * mail_RenameFolder - implementation of the RenameFolder action of right click options on the tree
3289
	 *
3290
	 * @param _action
3291
	 * @param _senders - the representation of the tree leaf to be manipulated
3292
	 */
3293
	mail_RenameFolder: function(_action,_senders) {
3294
		//action.id == 'rename'
3295
		//_senders.iface.id == target leaf / leaf to edit
3296
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
3297
		var OldFolderName = ftree.getLabel(_senders[0].id).replace(this._unseen_regexp,'');
3298
		var buttons = [
3299
			{text: this.egw.lang("Rename"), id: "rename", "class": "ui-priority-primary", image: 'edit', "default": true},
3300
			{text: this.egw.lang("Cancel"), id:"cancel"}
3301
		];
3302
		et2_dialog.show_prompt(function(_button_id, _value) {
3303
			var NewFolderName = null;
3304
			if (_value.length>0) NewFolderName = _value;
3305
			//alert(NewFolderName);
3306
			if (NewFolderName && NewFolderName.length>0)
3307
			{
3308
				switch (_button_id)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
3309
				{
3310
					case "rename":
3311
						egw.json('mail.mail_ui.ajax_renameFolder',[_senders[0].id, NewFolderName])
3312
							.sendRequest(true);
3313
						return;
3314
					case "cancel":
3315
				}
3316
			}
3317
		},
3318
		this.egw.lang("Rename Folder %1 to:",OldFolderName),
3319
		this.egw.lang("Rename Folder %1 ?",OldFolderName),
3320
		OldFolderName, buttons);
3321
	},
3322
3323
	/**
3324
	 * mail_MoveFolder - implementation of the MoveFolder action on the tree
3325
	 *
3326
	 * @param {egwAction} _action
3327
	 * @param {egwActionObject[]} _senders - the representation of the tree leaf to be manipulated
3328
	 * @param {egwActionObject} destination Drop target egwActionObject representing the destination
3329
	 */
3330
	mail_MoveFolder: function(_action,_senders,destination) {
3331
		if(!destination || !destination.id)
3332
		{
3333
			egw.debug('warn', "Move folder, but no target");
3334
			return;
3335
		}
3336
		var sourceProfile = _senders[0].id.split('::');
3337
		var targetProfile = destination.id.split('::');
3338
		if (sourceProfile[0]!=targetProfile[0])
3339
		{
3340
			egw.message(this.egw.lang('Moving Folders from one Mailaccount to another is not supported'),'error');
3341
			return;
3342
		}
3343
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
3344
		var src_label = _senders[0].id.replace(/^[0-9]+::/,'');
3345
		var dest_label = destination.id.replace(/^[0-9]+::/,'');
3346
3347
		var callback = function (_button)
3348
		{
3349
			if (_button == et2_dialog.YES_BUTTON)
3350
			{
3351
				egw.appName='mail';
3352
				egw.message (egw.lang('Folder %1 is moving to folder %2',src_label,dest_label ));
3353
				egw.loading_prompt('mail_moveFolder', true,'','#egw_fw_basecontainer');
3354
				for(var i = 0; i < _senders.length; i++)
3355
				{
3356
					egw.jsonq('mail.mail_ui.ajax_MoveFolder',[_senders[i].id, destination.id],
3357
						// Move is done (successfully or not), remove loading
3358
						function() {
3359
							var id = destination.id.split('::');
3360
							//refersh the top parent
3361
							ftree.refreshItem(id[0],null);
3362
							egw.loading_prompt('mail_moveFolder', false);
3363
						}
3364
					);
3365
				}
3366
			}
3367
		};
3368
		et2_dialog.show_dialog(callback, this.egw.lang('Are you sure you want to move folder %1 to folder %2?',
3369
			src_label, dest_label), this.egw.lang('Move folder'), {},et2_dialog.BUTTONS_YES_NO,  et2_dialog.WARNING_MESSAGE);
3370
	},
3371
3372
	/**
3373
	 * mail_DeleteFolder - implementation of the DeleteFolder action of right click options on the tree
3374
	 *
3375
	 * @param _action
3376
	 * @param _senders - the representation of the tree leaf to be manipulated
3377
	 */
3378
	mail_DeleteFolder: function(_action,_senders) {
3379
		//action.id == 'delete'
3380
		//_senders.iface.id == target leaf / leaf to edit
3381
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
3382
		var OldFolderName = ftree.getLabel(_senders[0].id).replace(this._unseen_regexp,'');
3383
		var buttons = [
3384
			{text: this.egw.lang("Yes"), id: "delete", "class": "ui-priority-primary", "default": true},
3385
			{text: this.egw.lang("Cancel"), id:"cancel"}
3386
		];
3387
		et2_dialog.show_dialog(function(_button_id, _value) {
3388
			switch (_button_id)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
3389
			{
3390
				case "delete":
3391
					egw.json('mail.mail_ui.ajax_deleteFolder',[_senders[0].id])
3392
						.sendRequest(true);
3393
					return;
3394
				case "cancel":
3395
			}
3396
		},
3397
		this.egw.lang("Do you really want to DELETE Folder %1 ?",OldFolderName)+" "+(ftree.hasChildren(_senders[0].id)?this.egw.lang("All subfolders will be deleted too, and all messages in all affected folders will be lost"):this.egw.lang("All messages in the folder will be lost")),
3398
		this.egw.lang("DELETE Folder %1 ?",OldFolderName),
3399
		OldFolderName, buttons);
3400
	},
3401
3402
	/**
3403
	 * Send names of uploaded files (again) to server, to process them: either copy to vfs or ask overwrite/rename
3404
	 *
3405
	 * @param _event
3406
	 * @param _file_count
3407
	 * @param {string?} _path where the file is uploaded to, default current directory
3408
	 */
3409
	uploadForImport: function(_event, _file_count, _path)
3410
	{
3411
		// path is probably not needed when uploading for file; maybe it is when from vfs
3412
		if(typeof _path == 'undefined')
3413
		{
3414
			//_path = this.get_path();
3415
		}
3416
		if (_file_count && !jQuery.isEmptyObject(_event.data.getValue()))
3417
		{
3418
			var widget = _event.data;
3419
//			var request = new egw_json_request('mail_ui::ajax_importMessage', ['upload', widget.getValue(), _path], this);
3420
//			widget.set_value('');
3421
//			request.sendRequest();//false, this._upload_callback, this);
3422
			this.et2_obj.submit();
3423
		}
3424
	},
3425
3426
	/**
3427
	 * Send names of uploaded files (again) to server, to process them: either copy to vfs or ask overwrite/rename
3428
	 *
3429
	 * @param {event object} _event
3430
	 * @param {string} _file_count
3431
	 * @param {string} _path [_path=current directory] Where the file is uploaded to.
3432
	 */
3433
	uploadForCompose: function(_event, _file_count, _path)
3434
	{
3435
		// path is probably not needed when uploading for file; maybe it is when from vfs
3436
		if(typeof _path == 'undefined')
3437
		{
3438
			//_path = this.get_path();
3439
		}
3440
		if (_file_count && !jQuery.isEmptyObject(_event.data.getValue()))
3441
		{
3442
			var widget = _event.data;
3443
			this.et2_obj.submit();
3444
		}
3445
	},
3446
3447
	/**
3448
	 * Visible attachment box in compose dialog as soon as the file starts to upload
3449
	 */
3450
	composeUploadStart: function ()
3451
	{
3452
		var boxAttachment = this.et2.getWidgetById('attachments');
3453
		if (boxAttachment)
3454
		{
3455
			var groupbox = boxAttachment.getParent();
3456
			if (groupbox) groupbox.set_disabled(false);
3457
		}
3458
		//Resize the compose dialog
3459
		var self = this;
3460
		setTimeout(function(){self.compose_resizeHandler();}, 100);
3461
		return true;
3462
	},
3463
3464
	/**
3465
	* Upload for import (VFS)
3466
	*
3467
	* @param {egw object} _egw
3468
	* @param {widget object} _widget
3469
	* @param {window object} _window
3470
	*/
3471
	vfsUploadForImport: function(_egw, _widget, _window) {
3472
		if (jQuery.isEmptyObject(_widget)) return;
3473
		if (!jQuery.isEmptyObject(_widget.getValue()))
3474
		{
3475
			this.et2_obj.submit();
3476
		}
3477
	},
3478
3479
	/**
3480
	* Upload for compose (VFS)
3481
	*
3482
	* @param {egw object} _egw
3483
	* @param {widget object} _widget
3484
	* @param {window object} _window
3485
	*/
3486
	vfsUploadForCompose: function(_egw, _widget, _window)
3487
	{
3488
		if (jQuery.isEmptyObject(_widget)) return;
3489
		if (!jQuery.isEmptyObject(_widget.getValue()))
3490
		{
3491
			this.et2_obj.submit();
3492
		}
3493
	},
3494
3495
	/**
3496
	* Submit on change (VFS)
3497
	*
3498
	* @param {egw object} _egw
3499
	* @param {widget object} _widget
3500
	*/
3501
	submitOnChange: function(_egw, _widget)
3502
	{
3503
		if (!jQuery.isEmptyObject(_widget))
3504
		{
3505
			if (typeof _widget.id !== 'undefined') var widgetId = _widget.id;
3506
			switch (widgetId)
0 ignored issues
show
Bug introduced by
The variable widgetId does not seem to be initialized in case typeof _widget.id !== "undefined" on line 3505 is false. Are you sure this can never be the case?
Loading history...
3507
			{
3508
				case 'mimeType':
3509
					this.et2_obj.submit();
3510
					break;
3511
				default:
3512
					if (!jQuery.isEmptyObject(_widget.getValue()))
3513
					{
3514
						this.et2_obj.submit();
3515
					}
3516
			}
3517
		}
3518
	},
3519
3520
	/**
3521
	 * Save as Draft (VFS)
3522
	 * -handel both actions save as draft and save as draft and print
3523
	 *
3524
	 * @param {egwAction} _egw_action
3525
	 * @param {array|string} _action string "autosaving", if that triggered the action
3526
	 */
3527
	saveAsDraft: function(_egw_action, _action)
3528
	{
3529
		//this.et2_obj.submit();
3530
		var content = this.et2.getArrayMgr('content').data;
3531
		var action = _action;
3532
		if (_egw_action && _action !== 'autosaving')
3533
		{
3534
			action = _egw_action.id;
3535
		}
3536
3537
		var widgets = ['from','to','cc','bcc','subject','folder','replyto','mailaccount',
3538
			'mail_htmltext', 'mail_plaintext', 'lastDrafted', 'filemode', 'expiration', 'password'];
3539
		var widget = {};
3540
		for (var index in widgets)
3541
		{
3542
			widget = this.et2.getWidgetById(widgets[index]);
3543
			if (widget)
3544
			{
3545
				content[widgets[index]] = widget.get_value();
3546
			}
3547
		}
3548
		var self = this;
3549
		if (content)
3550
		{
3551
			// if we compose an encrypted message, we have to get the encrypted content
3552
			if (this.mailvelope_editor)
3553
			{
3554
				this.mailvelope_editor.encrypt([]).then(function(_armored)
3555
				{
3556
					content['mail_plaintext'] = _armored;
3557
					self.egw.json('mail.mail_compose.ajax_saveAsDraft',[content, action],function(_data){
3558
						self.savingDraft_response(_data,action);
3559
					}).sendRequest(true);
3560
				}, function(_err)
3561
				{
3562
					self.egw.message(_err.message, 'error');
3563
				});
3564
				return false;
3565
			}
3566
3567
			this.egw.json('mail.mail_compose.ajax_saveAsDraft',[content, action],function(_data){
3568
				self.savingDraft_response(_data,action);
3569
			}).sendRequest(true);
3570
		}
3571
	},
3572
3573
	/**
3574
	 * Set content of drafted message with new information sent back from server
3575
	 * This function would be used as callback of send request to ajax_saveAsDraft.
3576
	 *
3577
	 * @param {object} _responseData response data sent back from server by ajax_saveAsDraft function.
3578
	 *  the object conatins below items:
3579
	 *  -draftedId: new drafted id created by server
3580
	 *  -message: resault message
3581
	 *  -success: true if saving was successful otherwise false
3582
	 *  -draftfolder: Name of draft folder including its delimiter
3583
	 *
3584
	 * @param {string} _action action is the element which caused saving draft, it could be as such:
3585
	 *  -button[saveAsDraft]
3586
	 *  -button[saveAsDraftAndPrint]
3587
	 *  -autosaving
3588
	 */
3589
	savingDraft_response: function(_responseData, _action)
3590
	{
3591
		//Make sure there's a response from server otherwise shoot an error message
3592
		if (jQuery.isEmptyObject(_responseData))
3593
		{
3594
			this.egw.message('Could not saved the message. Because, the response from server failed.', 'error');
3595
			return false;
3596
		}
3597
3598
		if (_responseData.success)
3599
		{
3600
			var content = this.et2.getArrayMgr('content');
3601
			var lastDrafted = this.et2.getWidgetById('lastDrafted');
3602
			var folderTree = typeof opener.etemplate2.getByApplication('mail')[0] !='undefined'?
3603
								opener.etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('nm[foldertree]'): null;
3604
			var activeFolder = folderTree?folderTree.getSelectedNode():null;
3605
			if (content)
3606
			{
3607
				var prevDraftedId = content.data.lastDrafted;
3608
				content.data.lastDrafted = _responseData.draftedId;
3609
				this.et2.setArrayMgr('content', content);
3610
				lastDrafted.set_value(_responseData.draftedId);
3611
				if (folderTree && activeFolder)
3612
				{
3613
					if (typeof activeFolder.id !='undefined' && _responseData.draftfolder == activeFolder.id)
3614
					{
3615
						if (prevDraftedId)
3616
						{
3617
							opener.egw_refresh(_responseData.message,'mail', prevDraftedId, 'delete');
3618
						}
3619
						this.egw.refresh(_responseData.message,'mail',_responseData.draftedId);
3620
					}
3621
				}
3622
				switch (_action)
3623
				{
3624
					case 'button[saveAsDraftAndPrint]':
3625
						this.mail_compose_print('mail::'+_responseData.draftedId);
3626
						this.egw.message(_responseData.message);
3627
						break;
3628
					case 'autosaving':
3629
						//Any sort of thing if it's an autosaving action
3630
					default:
3631
						this.egw.message(_responseData.message);
3632
				}
3633
			}
3634
		}
3635
		else
3636
		{
3637
			this.egw.message(_responseData.message, 'error');
3638
		}
3639
	},
3640
3641
	/**
3642
	 * Focus handler for folder, address, reject textbox/taglist to automatic check associated radio button
3643
	 *
3644
	 * @param {event} _ev
3645
	 * @param {object} _widget taglist
3646
	 *
3647
	 */
3648
	sieve_focus_radioBtn: function(_ev, _widget)
3649
	{
3650
		_widget.getRoot().getWidgetById('action').set_value(_widget.id.replace(/^action_([^_]+)_text$/, '$1'));
3651
	},
3652
3653
	/**
3654
	 * Select all aliases
3655
	 *
3656
	 */
3657
	sieve_vac_all_aliases: function()
3658
	{
3659
		var aliases = [];
3660
		var tmp = [];
3661
		var addr = this.et2.getWidgetById('addresses');
3662
		var addresses = this.et2.getArrayMgr('sel_options').data.addresses;
3663
3664
		for(var id in addresses) aliases.push(id);
3665
		if (addr)
3666
		{
3667
			tmp = aliases.concat(addr.get_value());
3668
3669
			// returns de-duplicate items of an array
3670
			var deDuplicator = function (item,pos)
3671
			{
3672
				return tmp.indexOf(item) == pos;
3673
			};
3674
3675
			aliases = tmp.filter(deDuplicator);
3676
			addr.set_value(aliases);
3677
		}
3678
	},
3679
3680
	/**
3681
	 * Disable/Enable date widgets on vacation seive rules form when status is "by_date"
3682
	 *
3683
	 */
3684
	vacationFilterStatusChange: function()
3685
	{
3686
		var status = this.et2.getWidgetById('status');
3687
		var s_date = this.et2.getWidgetById('start_date');
3688
		var e_date = this.et2.getWidgetById('end_date');
3689
		var by_date_label = this.et2.getWidgetById('by_date_label');
3690
3691
		if (status && s_date && e_date && by_date_label)
3692
		{
3693
			s_date.set_disabled(status.get_value() != "by_date");
3694
			e_date.set_disabled(status.get_value() != "by_date");
3695
			by_date_label.set_disabled(status.get_value() != "by_date");
3696
		}
3697
	},
3698
3699
	/**
3700
	 * action - handling actions on sieve rules
3701
	 *
3702
	 * @param _type - action name
3703
	 * @param _selected - selected row from the sieve rule list
3704
	 */
3705
	action: function(_type, _selected)
3706
	{
3707
		var  actionData ;
3708
		var that = this;
3709
		var typeId = _type.id;
3710
		var linkData = '';
3711
		var ruleID = ((_selected[0].id.split("_").pop()) - 1); // subtract the row id from 1 because the first row id is reserved by grid header
3712
		if (_type)
3713
		{
3714
3715
			switch (_type.id)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
3716
			{
3717
				case 'delete':
3718
3719
					var callbackDeleteDialog = function (button_id)
3720
					{
3721
						if (button_id == et2_dialog.YES_BUTTON )
3722
						{
3723
							actionData = _type.parent.data.widget.getArrayMgr('content');
3724
							that._do_action(typeId, actionData['data'],ruleID);
3725
						}
3726
					};
3727
					et2_dialog.show_dialog(callbackDeleteDialog, this.egw.lang("Do you really want to DELETE this Rule"),this.egw.lang("Delete"), {},et2_dialog.BUTTONS_YES_CANCEL, et2_dialog.WARNING_MESSAGE);
3728
3729
					break;
3730
				case 'add'	:
3731
					linkData = "mail.mail_sieve.edit";
3732
					this.egw.open_link(linkData,'_blank',"600x480");
3733
					break;
3734
				case 'edit'	:
3735
					linkData = "mail.mail_sieve.edit&ruleID="+ruleID;
3736
					this.egw.open_link(linkData,'_blank',"600x480");
3737
					break;
3738
				case 'enable':
3739
					actionData = _type.parent.data.widget.getArrayMgr('content');
3740
					this._do_action(typeId,actionData['data'],ruleID);
3741
					break;
3742
				case 'disable':
3743
					actionData = _type.parent.data.widget.getArrayMgr('content');
3744
					this._do_action(typeId,actionData['data'],ruleID);
3745
					break;
3746
3747
			}
3748
		}
3749
3750
	},
3751
3752
	/**
3753
	* Send back sieve action result to server
3754
	*
3755
	* @param {string} _typeID action name
3756
	* @param {object} _data content
3757
	* @param {string} _selectedID selected row id
3758
	* @param {string} _msg message
3759
	*
3760
	*/
3761
	_do_action: function(_typeID, _data,_selectedID,_msg)
3762
	{
3763
		if (_typeID && _data)
3764
		{
3765
			var request = this.egw.json('mail.mail_sieve.ajax_action', [_typeID,_selectedID,_msg],null,null,true);
3766
			request.sendRequest();
3767
		}
3768
	},
3769
3770
	/**
3771
	* Send ajax request to server to refresh the sieve grid
3772
	*/
3773
	sieve_refresh: function()
3774
	{
3775
		this.et2._inst.submit();
3776
	},
3777
3778
	/**
3779
	 * Select the right combination of the rights for radio buttons from the selected common right
3780
	 *
3781
	 * @@param {jQuery event} event
3782
	 * @param {widget} widget common right selectBox
3783
	 *
3784
	 */
3785
	acl_common_rights_selector: function(event,widget)
3786
	{
3787
		var rowId = widget.id.replace(/[^0-9.]+/g, '');
3788
		var rights = [];
3789
3790
		switch (widget.get_value())
3791
		{
3792
			case 'custom':
3793
				break;
3794
			case 'aeiklprstwx':
3795
				rights = widget.get_value().replace(/[k,x,t,e]/g,"cd").split("");
3796
				break;
3797
			default:
3798
				rights = widget.get_value().split("");
3799
		}
3800
		if (rights.length > 0)
3801
		{
3802
			for (var i=0;i<this.aclRights.length;i++)
3803
			{
3804
				var rightsWidget = this.et2.getWidgetById(rowId+'[acl_' + this.aclRights[i]+ ']');
3805
				rightsWidget.set_value((jQuery.inArray(this.aclRights[i],rights) != -1 )?true:false);
3806
			}
3807
		}
3808
	},
3809
3810
	/**
3811
	 *
3812
	 * Choose the right common right option for common ACL selecBox
3813
	 *
3814
	 * @param {jQuery event} event
3815
	 * @param {widget} widget radioButton rights
3816
	 *
3817
	 */
3818
	acl_common_rights: function(event, widget)
3819
	{
3820
	   var rowId = widget.id.replace(/[^0-9.]+/g, '');
3821
	   var aclCommonWidget = this.et2.getWidgetById(rowId + '[acl]');
3822
	   var rights = '';
3823
3824
	   for (var i=0;i<this.aclRights.length;i++)
3825
	   {
3826
		   var rightsWidget = this.et2.getWidgetById(rowId+'[acl_' + this.aclRights[i]+ ']');
3827
		   if (rightsWidget.get_value() == "true")
3828
			   rights += this.aclRights[i];
3829
3830
	   }
3831
3832
	   for (var i=0;i<this.aclCommonRights.length;i++)
3833
	   {
3834
		   if (rights.split("").sort().toString() == this.aclCommonRights[i].split("").sort().toString())
3835
			   rights = this.aclCommonRights[i];
3836
	   }
3837
	   if (jQuery.inArray(rights,this.aclCommonRights ) == -1 && rights !='lrswipcda')
3838
	   {
3839
		   aclCommonWidget.set_value('custom');
3840
	   }
3841
	   else if (rights =='lrswipcda')
3842
	   {
3843
           aclCommonWidget.set_value('aeiklprstwx');
3844
	   }
3845
	   else
3846
	   {
3847
		   aclCommonWidget.set_value(rights);
3848
	   }
3849
	},
3850
3851
	/**
3852
	 * Open seive filter list
3853
	 *
3854
	 * @param {action} _action
3855
	 * @param {sender} _senders
3856
	 *
3857
	 */
3858
	edit_sieve: function(_action, _senders)
3859
	{
3860
		var acc_id = parseInt(_senders[0].id);
3861
3862
		var url = this.egw.link('/index.php',{
3863
					'menuaction': 'mail.mail_sieve.index',
3864
					'acc_id': acc_id,
3865
					'ajax': 'true'
3866
		});
3867
3868
		// an ugly hack for idots to show up sieve rules not in an iframe
3869
		// but as new link, better to remove it after get rid of idots template
3870
		if (typeof window.framework == 'undefined')
3871
		{
3872
			this.egw.open_link(url);
3873
		}
3874
		else
3875
		{
3876
			this.loadIframe(url);
3877
		}
3878
	},
3879
3880
	/**
3881
	 * Load an url on an iframe
3882
	 *
3883
	 * @param {string} _url string egw url
3884
	 * @param {iframe widget} _iFrame an iframe to be set if non, extra_iframe is default
3885
	 *
3886
	 * @return {boolean} return TRUE if success, and FALSE if iframe not given
3887
	 */
3888
	loadIframe: function (_url, _iFrame)
3889
	{
3890
		var mailSplitter = this.et2.getWidgetById('splitter');
3891
		var quotaipercent = this.et2.getWidgetById('nm[quotainpercent]');
3892
		var iframe = _iFrame || this.et2.getWidgetById('extra_iframe');
3893
		if (typeof iframe != 'undefined' && iframe)
3894
		{
3895
			if (_url)
3896
			{
3897
				iframe.set_src(_url);
3898
			}
3899
			if (typeof mailSplitter != 'undefined' && mailSplitter && typeof quotaipercent != 'undefined')
3900
			{
3901
				mailSplitter.set_disabled(!!_url);
3902
				quotaipercent.set_disabled(!!_url);
3903
				iframe.set_disabled(!_url);
3904
			}
3905
			// extra_iframe used for showing up sieve rules
3906
			// need some special handling for mobile device
3907
			// as we wont have splitter, and also a fix for
3908
			// iframe with display none
3909
			if (iframe.id == "extra_iframe")
3910
			{
3911
				if (egwIsMobile())
3912
				{
3913
					var nm = this.et2.getWidgetById(this.nm_index);
3914
					nm.set_disabled(!!_url);
3915
					iframe.set_disabled(!_url);
3916
				}
3917
				// Set extra_iframe a class with height and width
3918
				// and position relative, seems iframe display none
3919
				// with 100% height/width covers mail tree and block
3920
				// therefore block the click handling
3921
				if (!iframe.disabled)
3922
				{
3923
					iframe.set_class('mail-index-extra-iframe');
3924
				}
3925
				else
3926
				{
3927
					iframe.set_class('');
3928
				}
3929
			}
3930
			return true;
3931
		}
3932
		return false;
3933
	},
3934
3935
	/**
3936
	 * Edit vacation message
3937
	 *
3938
	 * @param {action} _action
3939
	 * @param {sender} _senders
3940
	 */
3941
	edit_vacation: function(_action, _senders)
3942
	{
3943
		var acc_id = parseInt(_senders[0].id);
3944
		this.egw.open_link('mail.mail_sieve.editVacation&acc_id='+acc_id,'_blank','700x480');
3945
	},
3946
3947
	subscription_refresh: function(_data)
3948
	{
3949
		console.log(_data);
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
3950
	},
3951
3952
	/**
3953
	 * Submit on apply button and save current tree state
3954
	 *
3955
	 * @param {type} _egw
3956
	 * @param {type} _widget
3957
	 * @returns {undefined}
3958
	 */
3959
	subscription_apply: function (_egw, _widget)
3960
	{
3961
		var tree = etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('foldertree');
3962
		if (tree)
3963
		{
3964
			tree.input._xfullXML = true;
3965
			this.subscription_treeLastState = tree.input.serializeTreeToJSON();
3966
		}
3967
		this.et2._inst.submit(_widget);
3968
	},
3969
3970
	/**
3971
	 * Show ajax-loader when the autoloading get started
3972
	 *
3973
	 * @param {type} _id item id
3974
	 * @param {type} _widget tree widget
3975
	 * @returns {Boolean}
3976
	 */
3977
	subscription_autoloadingStart: function (_id, _widget)
3978
	{
3979
		var node = _widget.input._globalIdStorageFind(_id);
3980
		if (node && typeof node.htmlNode != 'undefined')
3981
		{
3982
			var img = jQuery('img',node.htmlNode)[0];
3983
			img.src = egw.image('ajax-loader', 'admin');
3984
		}
3985
		return true;
3986
	},
3987
3988
	/**
3989
	 * Revert back the icon after autoloading is finished
3990
	 * @returns {Boolean}
3991
	 */
3992
	subscription_autoloadingEnd: function ()
3993
	{
3994
		return true;
3995
	},
3996
3997
	/**
3998
	 * Popup the subscription dialog
3999
	 *
4000
	 * @param {action} _action
4001
	 * @param {sender} _senders
4002
	 */
4003
	edit_subscribe: function (_action,_senders)
4004
	{
4005
		var acc_id = parseInt(_senders[0].id);
4006
		this.egw.open_link('mail.mail_ui.subscription&acc_id='+acc_id, '_blank', '720x500');
4007
	},
4008
4009
	/**
4010
	 * Subscribe selected unsubscribed folder
4011
	 *
4012
	 * @param {action} _action
4013
	 * @param {sender} _senders
4014
	 */
4015
	subscribe_folder: function(_action,_senders)
4016
	{
4017
		var mailbox = _senders[0].id.split('::');
4018
		var folder = mailbox[1], acc_id = mailbox[0];
4019
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
4020
		this.egw.message(this.egw.lang('Subscribe to Folder %1',ftree.getLabel(_senders[0].id).replace(this._unseen_regexp,'')));
4021
		egw.json('mail.mail_ui.ajax_foldersubscription',[acc_id,folder,true])
4022
			.sendRequest();
4023
	},
4024
4025
	/**
4026
	 * Unsubscribe selected subscribed folder
4027
	 *
4028
	 * @param {action} _action
4029
	 * @param {sender} _senders
4030
	 */
4031
	unsubscribe_folder: function(_action,_senders)
4032
	{
4033
		var mailbox = _senders[0].id.split('::');
4034
		var folder = mailbox[1], acc_id = mailbox[0];
4035
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
4036
		this.egw.message(this.egw.lang('Unsubscribe from Folder %1',ftree.getLabel(_senders[0].id).replace(this._unseen_regexp,'')));
4037
		egw.json('mail.mail_ui.ajax_foldersubscription',[acc_id,folder,false])
4038
			.sendRequest();
4039
	},
4040
4041
	/**
4042
	 * Onclick for node/foldername in subscription popup
4043
	 *
4044
	 * Used to (un)check node including all children
4045
	 *
4046
	 * @param {string} _id id of clicked node
4047
	 * @param {et2_tree} _widget reference to tree widget
4048
	 */
4049
	subscribe_onclick: function(_id, _widget)
4050
	{
4051
		_widget.setSubChecked(_id, "toggle");
4052
	},
4053
4054
	/**
4055
	 * Edit a folder acl for account(s)
4056
	 *
4057
	 * @param _action
4058
	 * @param _senders - the representation of the tree leaf to be manipulated
4059
	 */
4060
	edit_acl: function(_action, _senders)
4061
	{
4062
		var mailbox = _senders[0].id.split('::');
4063
		var folder = mailbox[1] || 'INBOX', acc_id = mailbox[0];
4064
		this.egw.open_link('mail.mail_acl.edit&mailbox='+ jQuery.base64Encode(folder)+'&acc_id='+acc_id, '_blank', '640x480');
4065
	},
4066
4067
	/**
4068
	 * Submit new selected folder back to server in order to read its acl's rights
4069
	 */
4070
	acl_folderChange: function ()
4071
	{
4072
		var mailbox = this.et2.getWidgetById('mailbox');
4073
4074
		if (mailbox)
4075
		{
4076
			if (mailbox.taglist.getValue().length > 0)
4077
			{
4078
				this.et2._inst.submit();
4079
			}
4080
		}
4081
	},
4082
4083
	/**
4084
	 * Edit a mail account
4085
	 *
4086
	 * @param _action
4087
	 * @param _senders - the representation of the tree leaf to be manipulated
4088
	 */
4089
	edit_account: function(_action, _senders)
4090
	{
4091
		var acc_id = parseInt(_senders[0].id);
4092
		this.egw.open_link('mail.mail_wizard.edit&acc_id='+acc_id, '_blank', '720x500');
4093
	},
4094
4095
	/**
4096
	 * Set expandable fields (Folder, Cc and Bcc) based on their content
4097
	 * - Only fields which have no content should get hidden
4098
	 */
4099
	compose_fieldExpander_init: function ()
4100
	{
4101
		var widgets = {
4102
			cc:{
4103
				widget:{},
4104
				jQClass: '.mailComposeJQueryCc'
4105
			},
4106
			bcc:{
4107
				widget:{},
4108
				jQClass: '.mailComposeJQueryBcc'
4109
			},
4110
			folder:{
4111
				widget:{},
4112
				jQClass: '.mailComposeJQueryFolder'
4113
			},
4114
			replyto:{
4115
				widget:{},
4116
				jQClass: '.mailComposeJQueryReplyto'
4117
			}};
4118
4119
		for(var widget in widgets)
4120
		{
4121
			var expanderBtn = widget + '_expander';
4122
			widgets[widget].widget = this.et2.getWidgetById(widget);
4123
			// Add expander button widget to the widgets object
4124
			widgets[expanderBtn] = {widget:this.et2.getWidgetById(expanderBtn)};
4125
4126
			if (typeof widgets[widget].widget != 'undefined'
4127
					&& typeof widgets[expanderBtn].widget != 'undefined'
4128
					&& widgets[widget].widget.get_value().length == 0)
4129
			{
4130
				widgets[expanderBtn].widget.set_disabled(false);
4131
				jQuery(widgets[widget].jQClass).hide();
4132
			}
4133
		}
4134
	},
4135
4136
	/**
4137
	 * Control textArea size based on available free space at the bottom
4138
	 *
4139
	 */
4140
	compose_resizeHandler: function()
4141
	{
4142
		// Do not resize compose dialog if it's running on mobile device
4143
		// in this case user would be able to edit mail body by scrolling down,
4144
		// which is more convenient on small devices. Also resize mailbody with
4145
		// ckeditor may causes performance regression, especially on devices with
4146
		// very limited resources and slow proccessor.
4147
		if (egwIsMobile()) return false;
4148
4149
		try {
4150
			var bodyH = egw_getWindowInnerHeight();
4151
			var textArea = this.et2.getWidgetById('mail_plaintext');
4152
			var $headerSec = jQuery('.mailComposeHeaderSection');
4153
			var attachments = this.et2.getWidgetById('attachments');
4154
			var content = this.et2.getArrayMgr('content').data;
4155
4156
			// @var arrbitary int represents px
4157
			// Visible height of attachment progress
4158
			var prgV_H = 150;
4159
4160
			// @var arrbitary int represents px
4161
			// Visible height of attchements list
4162
			var attchV_H = 68;
4163
4164
			if (typeof textArea != 'undefined' && textArea != null)
4165
			{
4166
				if (textArea.getParent().disabled)
4167
				{
4168
					textArea = this.et2.getWidgetById('mail_htmltext');
4169
				}
4170
				// Tolerate values base on plain text or html, in order to calculate freespaces
4171
				var textAreaDelta = textArea.id == "mail_htmltext"?20:40;
4172
4173
				// while attachments are in progress take progress visiblity into account
4174
				// otherwise the attachment progress is finished and consider attachments list
4175
				var delta = (attachments.table.find('li').length>0 && attachments.table.height() > 0)? prgV_H: (content.attachments? attchV_H: textAreaDelta);
4176
4177
				var bodySize = (bodyH  - Math.round($headerSec.height() + $headerSec.offset().top) - delta);
4178
4179
				if (textArea.id != "mail_htmltext")
4180
				{
4181
					textArea.getParent().set_height(bodySize);
4182
					textArea.set_height(bodySize);
4183
				}
4184
				else if (typeof textArea != 'undefined' && textArea.id == 'mail_htmltext')
4185
				{
4186
					textArea.ckeditor.resize('100%', bodySize);
4187
				}
4188
				else
4189
				{
4190
					textArea.set_height(bodySize - 90);
4191
				}
4192
			}
4193
		}
4194
		catch(e) {
4195
			// ignore errors causing compose to load twice
4196
		}
4197
	},
4198
4199
	/**
4200
	 * Display Folder,Cc or Bcc fields in compose popup
4201
	 *
4202
	 * @param {jQuery event} event
4203
	 * @param {widget object} widget clicked label (Folder, Cc or Bcc) from compose popup
4204
	 *
4205
	 */
4206
	compose_fieldExpander: function(event,widget)
4207
	{
4208
		var expWidgets = {cc:{},bcc:{},folder:{},replyto:{}};
4209
		for (var name in expWidgets)
4210
		{
4211
			expWidgets[name] = this.et2.getWidgetById(name+'_expander');
4212
		}
4213
4214
		if (typeof widget !='undefined')
4215
		{
4216
			switch (widget.id)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
4217
			{
4218
				case 'cc_expander':
4219
					jQuery(".mailComposeJQueryCc").show();
4220
					if (typeof expWidgets.cc !='undefined')
4221
					{
4222
						expWidgets.cc.set_disabled(true);
4223
					}
4224
					break;
4225
				case 'bcc_expander':
4226
					jQuery(".mailComposeJQueryBcc").show();
4227
					if (typeof expWidgets.bcc !='undefined')
4228
					{
4229
						expWidgets.bcc.set_disabled(true);
4230
					}
4231
					break;
4232
				case 'folder_expander':
4233
					jQuery(".mailComposeJQueryFolder").show();
4234
					if (typeof expWidgets.folder !='undefined')
4235
					{
4236
						expWidgets.folder.set_disabled(true);
4237
					}
4238
					break;
4239
				case 'replyto_expander':
4240
					jQuery(".mailComposeJQueryReplyto").show();
4241
					if (typeof expWidgets.replyto !='undefined')
4242
					{
4243
						expWidgets.replyto.set_disabled(true);
4244
					}
4245
					break;
4246
			}
4247
		}
4248
		else if (typeof widget == "undefined")
4249
		{
4250
			var widgets = {cc:{},bcc:{},folder:{},replyto:{}};
4251
4252
			for(var widget in widgets)
4253
			{
4254
				widgets[widget] = this.et2.getWidgetById(widget);
4255
4256
				if (widgets[widget].get_value().length)
4257
				{
4258
					switch (widget)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
4259
					{
4260
						case 'cc':
4261
							jQuery(".mailComposeJQueryCc").show();
4262
							if (typeof expWidgets.cc != 'undefiend')
4263
							{
4264
								expWidgets.cc.set_disabled(true);
4265
							}
4266
							break;
4267
						case 'bcc':
4268
							jQuery(".mailComposeJQueryBcc").show();
4269
							if (typeof expWidgets.bcc != 'undefiend')
4270
							{
4271
								expWidgets.bcc.set_disabled(true);
4272
							}
4273
							break;
4274
						case 'folder':
4275
							jQuery(".mailComposeJQueryFolder").show();
4276
							if (typeof expWidgets.folder != 'undefiend')
4277
							{
4278
								expWidgets.folder.set_disabled(true);
4279
							}
4280
							break;
4281
						case 'replyto':
4282
							jQuery(".mailComposeJQueryReplyto").show();
4283
							if (typeof expWidgets.replyto != 'undefiend')
4284
							{
4285
								expWidgets.replyto.set_disabled(true);
4286
							}
4287
							break;
4288
					}
4289
				}
4290
			}
4291
		}
4292
		this.compose_resizeHandler();
4293
	},
4294
4295
	/**
4296
	 * Lock tree so it does NOT receive any more mouse-clicks
4297
	 */
4298
	lock_tree: function()
4299
	{
4300
		if (!document.getElementById('mail_folder_lock_div'))
4301
		{
4302
			var parent = jQuery('#mail-index_nm\\[foldertree\\]');
4303
			var lock_div = jQuery(document.createElement('div'));
4304
			lock_div.attr('id', 'mail_folder_lock_div')
4305
				.addClass('mail_folder_lock');
4306
			parent.prepend(lock_div);
4307
		}
4308
	},
4309
4310
	/**
4311
	 * Unlock tree so it receives again mouse-clicks after calling lock_tree()
4312
	 */
4313
	unlock_tree: function()
4314
	{
4315
		jQuery('#mail_folder_lock_div').remove();
4316
	},
4317
4318
	/**
4319
	 * Called when tree opens up an account or folder
4320
	 *
4321
	 * @param {String} _id account-id[::folder-name]
4322
	 * @param {et2_widget_tree} _widget
4323
	 * @param {Number} _hasChildren 0 - item has no child nodes, -1 - item is closed, 1 - item is opened
4324
	 */
4325
	openstart_tree: function(_id, _widget, _hasChildren)
4326
	{
4327
		if (_id.indexOf('::') == -1 &&	// it's an account, not a folder in an account
4328
			!_hasChildren)
4329
		{
4330
			this.lock_tree();
4331
		}
4332
		return true;	// allow opening of node
4333
	},
4334
4335
	/**
4336
	 * Called when tree opens up an account or folder
4337
	 *
4338
	 * @param {String} _id account-id[::folder-name]
4339
	 * @param {et2_widget_tree} _widget
4340
	 * @param {Number} _hasChildren 0 - item has no child nodes, -1 - item is closed, 1 - item is opened
4341
	 */
4342
	openend_tree: function(_id, _widget, _hasChildren)
4343
	{
4344
		if (_id.indexOf('::') == -1 &&	// it's an account, not a folder in an account
4345
			_hasChildren == 1)
4346
		{
4347
			this.unlock_tree();
4348
		}
4349
	},
4350
4351
	/**
4352
	 * Print a mail from list
4353
4354
	 * @param _action
4355
	 * @param _senders - the representation of the tree leaf to be manipulated
4356
	 */
4357
	mail_print: function(_action, _senders)
4358
	{
4359
		var currentTemp = this.et2._inst.name;
4360
4361
		switch (currentTemp)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
4362
		{
4363
			case 'mail.index':
4364
				this.mail_prev_print(_action, _senders);
4365
				break;
4366
			case 'mail.display':
4367
				this.mail_display_print();
4368
		}
4369
4370
	},
4371
4372
	/**
4373
	 * Print a mail from compose
4374
	 * @param {stirng} _id id of new draft
4375
	 */
4376
	mail_compose_print:function (_id)
4377
	{
4378
		this.egw.open(_id,'mail','view','&print='+_id+'&mode=print');
4379
	},
4380
4381
	/**
4382
	 * Bind special handler on print media.
4383
	 * -FF and IE have onafterprint event, and as Chrome does not have that event we bind afterprint function to onFocus
4384
	 */
4385
	print_for_compose: function()
4386
	{
4387
		var afterprint = function (){
4388
			egw(window).close();
4389
		};
4390
4391
		if (!window.onafterprint)
4392
		{
4393
			// For browsers which does not support onafterprint event, eg. Chrome
4394
			setTimeout(function() {
4395
				egw(window).close();
4396
			}, 2000);
4397
		}
4398
		else
4399
		{
4400
			window.onafterprint = afterprint;
4401
		}
4402
	},
4403
4404
	/**
4405
	 * Prepare display dialog for printing
4406
	 * copies iframe content to a DIV, as iframe causes
4407
	 * trouble for multipage printing
4408
	 * @param {jQuery object} _iframe mail body iframe
4409
	 * @returns {undefined}
4410
	 */
4411
	mail_prepare_print: function(_iframe)
4412
	{
4413
		var $mainIframe = _iframe || jQuery('#mail-display_mailDisplayBodySrc');
4414
		var tmpPrintDiv = jQuery('#tempPrintDiv');
4415
4416
		if (tmpPrintDiv.length == 0 && tmpPrintDiv.children())
4417
		{
4418
			tmpPrintDiv = jQuery(document.createElement('div'))
4419
							.attr('id', 'tempPrintDiv')
4420
							.addClass('tmpPrintDiv');
4421
			var notAttached = true;
4422
		}
4423
4424
		if ($mainIframe)
4425
		{
4426
			tmpPrintDiv[0].innerHTML = $mainIframe.contents().find('body').html();
4427
		}
4428
		// Attach the element to the DOM after maniupulation
4429
		if (notAttached) $mainIframe.after(tmpPrintDiv);
4430
		tmpPrintDiv.find('#divAppboxHeader').remove();
4431
4432
	},
4433
4434
	/**
4435
	 * Print a mail from Display
4436
	 */
4437
	mail_display_print: function ()
4438
	{
4439
		this.egw.message('Printing....');
4440
4441
		// Make sure the print happens after the content is loaded. Seems Firefox and IE can't handle timing for print command correctly
4442
		setTimeout(function(){
4443
			egw(window).window.print();
4444
		},100);
4445
	},
4446
4447
	/**
4448
	 * Print a mail from list
4449
	 *
4450
	 * @param {Object} _action
4451
	 * @param {Object} _elems
4452
	 *
4453
	 */
4454
	mail_prev_print: function (_action, _elems)
4455
	{
4456
		this.mail_open(_action, _elems, 'print');
4457
	},
4458
4459
	/**
4460
	 * Print a mail from list
4461
	 *
4462
	 * @param {egw object} _egw
4463
	 * @param {widget object} _widget mail account selectbox
4464
	 *
4465
	 */
4466
	vacation_change_account: function (_egw, _widget)
4467
	{
4468
		_widget.getInstanceManager().submit();
4469
	},
4470
4471
	/**
4472
	 * OnChange callback for recipients:
4473
	 * - make them draggable
4474
	 * - check if we have keys for recipients, if we compose an encrypted mail
4475
	 **/
4476
	recipients_onchange: function()
4477
	{
4478
		// if we compose an encrypted mail, check if we have keys for new recipient
4479
		if (this.mailvelope_editor)
4480
		{
4481
			var self = this;
4482
			this.mailvelopeGetCheckRecipients().catch(function(_err)
4483
			{
4484
				self.egw.message(_err.message, 'error');
4485
			});
4486
		}
4487
		this.set_dragging_dndCompose();
4488
	},
4489
4490
	/**
4491
	 * Make recipients draggable
4492
	 */
4493
	set_dragging_dndCompose: function ()
4494
	{
4495
		var zIndex = 100;
4496
		var dragItems = jQuery('div.ms-sel-item:not(div.ui-draggable)');
4497
		dragItems.each(function(i,item){
4498
				var $isErr = jQuery(item).find('.ui-state-error');
4499
				if ($isErr.length > 0)
4500
				{
4501
					delete dragItems.splice(i,1);
4502
				}
4503
			});
4504
		if (dragItems.length > 0)
4505
		{
4506
			dragItems.draggable({
4507
				appendTo:'body',
4508
				//Performance wise better to not add ui-draggable class to items since we are not using that class
4509
				containment:'document',
4510
				distance: 0,
4511
				cursor:'move',
4512
				cursorAt:{left:2},
4513
				//cancel dragging on close button to avoid conflict with close action
4514
				cancel:'.ms-close-btn',
4515
				delay: '300',
4516
				/**
4517
				 * function to act on draggable item on revert's event
4518
				 * @returns {Boolean} return true
4519
				 */
4520
				revert: function (){
4521
					this.parent().find('.ms-sel-item').css('position','relative');
4522
					var $input = this.parent().children('input');
4523
					// Make sure input field not getting into second line after revert
4524
					$input.width($input.width()-10);
4525
					return true;
4526
				},
4527
				/**
4528
				 * function to act as draggable starts dragging
4529
				 *
4530
				 * @param {type} event
4531
				 * @param {type} ui
4532
				 */
4533
				start:function(event, ui)
4534
				{
4535
					var dragItem = jQuery(this);
4536
					if (event.ctrlKey || event.metaKey)
4537
					{
4538
						dragItem.addClass('mailCompose_copyEmail')
4539
								.css('cursor','copy');
4540
					}
4541
					dragItem.css ('z-index',zIndex++);
4542
					dragItem.css('position','absolute');
4543
				},
4544
				/**
4545
				 *
4546
				 * @param {type} event
4547
				 * @param {type} ui
4548
				 */
4549
				create:function(event,ui)
4550
				{
4551
					jQuery(this).css('css','move');
4552
				}
4553
			}).draggable('disable');
4554
			window.setTimeout(function(){
4555
4556
				if(dragItems && dragItems.data() && typeof dragItems.data()['uiDraggable'] !== 'undefined') dragItems.draggable('enable');
4557
			},100);
4558
		}
4559
4560
	},
4561
4562
	/**
4563
	 * Initialize dropping targets for draggable emails
4564
	 * -
4565
	 */
4566
	init_dndCompose: function ()
4567
	{
4568
4569
		var self = this;
4570
		var emailTags = jQuery('#mail-compose_to,#mail-compose_cc,#mail-compose_bcc');
4571
		//Call to make new items draggable
4572
		emailTags.hover(function(){
4573
			self.set_dragging_dndCompose();
4574
		});
4575
		//Make used email-tag list widgets in mail compose droppable
4576
		emailTags.droppable({
4577
			accept:'.ms-sel-item',
4578
4579
			/**
4580
			 * Run after a draggable email item dropped over one of the email-taglists
4581
			 * -Set the dropped item to the dropped current target widget
4582
			 *
4583
			 * @param {type} event
4584
			 * @param {type} ui
4585
			 */
4586
			drop:function (event, ui)
4587
			{
4588
				var widget = self.et2.getWidgetById(this.getAttribute('name'));
4589
				var emails, distLists = [];
4590
				var fromWidget = {};
4591
4592
				var parentWidgetDOM = ui.draggable.parentsUntil('div[id^="mail-compoe_"]','.ui-droppable');
4593
				if (parentWidgetDOM != 'undefined' && parentWidgetDOM.length > 0)
4594
				{
4595
					fromWidget = self.et2.getWidgetById(parentWidgetDOM.attr('name'));
4596
				}
4597
4598
				var draggedValue = ui.draggable.text();
4599
4600
				// index of draggable item in selection list
4601
				var dValueKey = draggedValue;
4602
4603
				var distItem = ui.draggable.find('.mailinglist');
4604
				if (distItem.length>0)
4605
				{
4606
					var distItemId = parseInt(distItem.attr('data'));
4607
					if (distItemId)
4608
					{
4609
						var fromDistLists = resolveDistList(fromWidget);
4610
						for (var i=0;i<fromDistLists.length;i++)
4611
						{
4612
							if (distItemId == fromDistLists[i]['id'])
4613
							{
4614
								draggedValue = fromDistLists[i];
4615
								// dist list item index
4616
								dValueKey = fromDistLists[i]['id'];
4617
							}
4618
						}
4619
					}
4620
				}
4621
4622
				if (typeof widget != 'undefined')
4623
				{
4624
					emails = widget.get_value();
4625
					if (emails) emails = emails.concat([draggedValue]);
4626
4627
					// Resolve the dist list and normal emails
4628
					distLists = resolveDistList(widget, emails);
4629
4630
					// Add normal emails
4631
					if (emails) widget.set_value(emails);
4632
4633
					// check if there's any dist list to be added
4634
					if (distLists.length>0) widget.taglist.addToSelection(distLists);
4635
4636
					if (!jQuery.isEmptyObject(fromWidget)
4637
							&& !(ui.draggable.attr('class').search('mailCompose_copyEmail') > -1))
4638
					{
4639
						if (widget.node != fromWidget.node && !_removeDragged(fromWidget, dValueKey))
4640
						{
4641
							//Not successful remove, returns the item to its origin
4642
							jQuery(ui.draggable).draggable('option','revert',true);
4643
						}
4644
					}
4645
					else
4646
					{
4647
						ui.draggable
4648
								.removeClass('mailCompose_copyEmail')
4649
								.css('cursor','move');
4650
					}
4651
4652
					var dragItems = jQuery('div.ms-sel-item');
4653
					dragItems.each(function(i,item){
4654
						var $isErr = jQuery(item).find('.ui-state-error');
4655
						if ($isErr.length > 0)
4656
						{
4657
							delete dragItems.splice(i,1);
4658
						}
4659
					});
4660
				}
4661
			}
4662
		});
4663
4664
		/**
4665
		 * Remove dragged item from the widget which the item was dragged
4666
		 *
4667
		 * @param {type} _widget
4668
		 * @param {type} _value
4669
		 * @return {boolean} true if successul | false unsuccessul
4670
		 */
4671
		var _removeDragged = function (_widget, _value)
4672
		{
4673
			if (_widget && _value)
4674
			{
4675
				var emails = _widget.get_value();
4676
				var itemIndex = emails.indexOf(_value);
4677
				var dist = [];
4678
				if (itemIndex > -1)
4679
				{
4680
					emails.splice(itemIndex,1);
4681
					// Resolve the dist list and normal emails
4682
					var dist = resolveDistList(_widget, emails);
4683
4684
					// Add normal emails
4685
					_widget.set_value(emails);
4686
4687
					//check if there's any dist list to be added
4688
					if (dist)
4689
					{
4690
						for(var i=0;i<dist.length;i++)
4691
						{
4692
							if (dist[i]['id'] == _value) dist.splice(i,1);
4693
						}
4694
						_widget.taglist.addToSelection(dist);
4695
					}
4696
				}
4697
				else
4698
				{
4699
					return false;
4700
				}
4701
			}
4702
			return true;
4703
		};
4704
4705
		/**
4706
		 * Resolve taglist widget which has distribution list
4707
		 *
4708
		 * @param {type} _widget
4709
		 * @param {type} _emails
4710
		 * @returns {Array} returns an array of distribution lists in selected widget
4711
		 */
4712
		var resolveDistList = function (_widget, _emails)
4713
		{
4714
			var list = [];
4715
			var selectedList = _widget.taglist.getSelection();
4716
			// Make a list of distribution list from the selection
4717
			for (var i=0;i<selectedList.length;i++)
4718
			{
4719
				if (!isNaN(selectedList[i]['id']) && selectedList[i]['class'] === 'mailinglist')
4720
				{
4721
					list.push(selectedList[i]);
4722
				}
4723
			}
4724
4725
			// Remove dist list from emails list
4726
			for(var key in _emails)
4727
			{
4728
				if (!isNaN(_emails[key]))
4729
				{
4730
					_emails.splice(key,1);
4731
				}
4732
			}
4733
			// returns distlist
4734
			return list;
4735
		};
4736
	},
4737
4738
	/**
4739
	* Check sharing mode and disable not available options
4740
	*
4741
	* @param {DOMNode} _node
4742
	* @param {et2_widget} _widget
4743
	*/
4744
	check_sharing_filemode: function(_node, _widget)
4745
	{
4746
		if (!_widget) _widget = this.et2.getWidgetById('filemode');
4747
4748
		var extended_settings = _widget.get_value() != 'attach' && this.egw.app('stylite');
4749
		this.et2.getWidgetById('expiration').set_readonly(!extended_settings);
4750
		this.et2.getWidgetById('password').set_readonly(!extended_settings);
4751
4752
		if (_widget.get_value() == 'share_rw' && !this.egw.app('stylite'))
4753
		{
4754
			this.egw.message(this.egw.lang('Writable sharing requires EPL version!'), 'info');
4755
			_widget.set_value('share_ro');
4756
		}
4757
	},
4758
4759
	/**
4760
	 * Write / update compose window title with subject
4761
	 *
4762
	 * @param {DOMNode} _node
4763
	 * @param {et2_widget} _widget
4764
	 */
4765
	subject2title: function(_node, _widget)
4766
	{
4767
		if (!_widget) _widget = this.et2.getWidgetById('subject');
4768
4769
		if (_widget && _widget.get_value())
4770
		{
4771
			document.title = _widget.get_value();
4772
		}
4773
	},
4774
4775
	/**
4776
	 * Clear intervals stored in W_INTERVALS which assigned to window
4777
	 */
4778
	clearIntevals: function ()
4779
	{
4780
		for(var i=0;i<this.W_INTERVALS.length;i++)
4781
		{
4782
			clearInterval(this.W_INTERVALS[i]);
4783
			delete this.W_INTERVALS[i];
4784
		}
4785
	},
4786
4787
	/**
4788
	 * Window title getter function in order to set the window title
4789
	 *
4790
	 * @returns {string|undefined} window title
4791
	 */
4792
	getWindowTitle: function ()
4793
	{
4794
		var widget = {};
4795
		switch(this.et2._inst.name)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
4796
		{
4797
			case 'mail.display':
4798
				widget = this.et2.getWidgetById('mail_displaysubject');
4799
				if (widget) return widget.options.value;
4800
				break;
4801
			case 'mail.compose':
4802
				widget = this.et2.getWidgetById('subject');
4803
				if (widget) return widget.get_value();
4804
				break;
4805
		}
4806
		return undefined;
4807
	},
4808
4809
	/**
4810
	 *
4811
	 * @returns {undefined}
4812
	 */
4813
	prepareMailvelopePrint: function()
4814
	{
4815
		var tempPrint = jQuery('div#tempPrintDiv');
4816
		var mailvelopeTopContainer = jQuery('div.mailDisplayContainer');
4817
		var originFrame = jQuery('#mail-display_mailDisplayBodySrc');
4818
		var iframe = jQuery(this.mailvelope_iframe_selector);
4819
4820
		if (tempPrint.length >0)
4821
		{
4822
			// Mailvelope iframe height is approximately equal to the height of encrypted origin message
4823
			// we add an arbitary plus pixels to make sure it's covering the full content in print view and
4824
			// it is not getting acrollbar in normal view
4825
			// @TODO: after Mailvelope plugin provides a hieght value, we can replace the height with an accurate value
4826
			iframe.addClass('mailvelopeIframe').height(originFrame[0].contentWindow.document.body.scrollHeight + 400);
4827
			tempPrint.hide();
4828
			mailvelopeTopContainer.addClass('mailvelopeTopContainer');
4829
		}
4830
	},
4831
4832
	/**
4833
	 * Mailvelope (clientside PGP) integration:
4834
	 * - detect Mailvelope plugin and open "egroupware" keyring (app_base.mailvelopeAvailable and _mailvelopeOpenKeyring)
4835
	 * - display and preview of encrypted messages (mailvelopeDisplay)
4836
	 * - button to toggle between regular and encrypted mail (togglePgpEncrypt)
4837
	 * - compose encrypted messages (mailvelopeCompose, compose_submitAction)
4838
	 * - fix autosave and save as draft to store encrypted content (saveAsDraft)
4839
	 * - fix inline reply to encrypted message to clientside decrypt message and add signature (mailvelopeCompose)
4840
	 */
4841
4842
	/**
4843
	 * Called on load of preview or display iframe, if mailvelope is available
4844
	 *
4845
	 * @param {Keyring} _keyring Mailvelope keyring to use
4846
	 * @ToDo signatures
4847
	 */
4848
	mailvelopeDisplay: function(_keyring)
4849
	{
4850
		var self = this;
4851
		var mailvelope = window.mailvelope;
4852
		var iframe = jQuery('iframe#mail-display_mailDisplayBodySrc,iframe#mail-index_messageIFRAME');
4853
		var armored = iframe.contents().find('td.td_display > pre').text().trim();
4854
4855
		if (armored == "" || armored.indexOf(this.begin_pgp_message) === -1) return;
4856
4857
		var container = iframe.parent()[0];
4858
		var container_selector = container.id ? '#'+container.id : 'div.mailDisplayContainer';
4859
4860
		options = {
4861
			showExternalContent: this.egw.preference('allowExternalIMGs') == 1	// "1", or "0", undefined --> true or false
4862
		};
4863
		// get sender address, so Mailvelope can check signature
4864
		var from_widget = this.et2.getWidgetById('FROM_0') || this.et2.getWidgetById('previewFromAddress');
4865
		if (from_widget && from_widget.value)
4866
		{
4867
			options.senderAddress = from_widget.value.replace(/^.*<([^<>]+)>$/, '$1');
4868
		}
4869
		mailvelope.createDisplayContainer(container_selector, armored, _keyring, options).then(function()
4870
		{
4871
			// hide our iframe to give space for mailvelope iframe with encrypted content
4872
			iframe.hide();
4873
			self.prepareMailvelopePrint();
4874
		},
4875
		function(_err)
4876
		{
4877
			self.egw.message(_err.message, 'error');
4878
		});
4879
	},
4880
4881
	/**
4882
	 * Editor object of active compose
4883
	 *
4884
	 * @var {Editor}
4885
	 */
4886
	mailvelope_editor: undefined,
4887
4888
	/**
4889
	 * Called on compose, if mailvelope is available
4890
	 *
4891
	 * @param {Keyring} _keyring Mailvelope keyring to use
4892
	 */
4893
	mailvelopeCompose: function(_keyring)
4894
	{
4895
		delete this.mailvelope_editor;
4896
4897
		// currently Mailvelope only supports plain-text, to this is unnecessary
4898
		var mimeType = this.et2.getWidgetById('mimeType');
4899
		var is_html = mimeType.get_value();
4900
		var container = is_html ? '.mailComposeHtmlContainer' : '.mailComposeTextContainer';
4901
		var editor = this.et2.getWidgetById(is_html ? 'mail_htmltext' : 'mail_plaintext');
4902
		var options = { predefinedText: editor.get_value() };
4903
4904
		// check if we have some sort of reply to an encrypted message
4905
		// --> parse header, encrypted mail to quote and signature so Mailvelope understands it
4906
		var start_pgp = options.predefinedText.indexOf(this.begin_pgp_message);
4907
		if (start_pgp != -1)
4908
		{
4909
			var end_pgp = options.predefinedText.indexOf(this.end_pgp_message);
4910
			if (end_pgp != -1)
4911
			{
4912
				options = {
4913
					quotedMailHeader: options.predefinedText.slice(0, start_pgp).replace(/> /mg, '').trim()+"\n",
4914
					quotedMail: options.predefinedText.slice(start_pgp, end_pgp+this.end_pgp_message.length+1).replace(/> /mg, ''),
4915
					quotedMailIndent: start_pgp != 0,
4916
					predefinedText: options.predefinedText.slice(end_pgp+this.end_pgp_message.length+1).replace(/^> \s*/m,''),
4917
					signMsg: true	// for now (no UI) always sign, when we encrypt
4918
				};
4919
				// set encrypted checkbox, if not already set
4920
				var composeToolbar = this.et2.getWidgetById('composeToolbar');
4921
				if (!composeToolbar.checkbox('pgp'))
4922
				{
4923
					composeToolbar.checkbox('pgp',true);
4924
				}
4925
			}
4926
		}
4927
4928
		var self = this;
4929
		mailvelope.createEditorContainer(container, _keyring, options).then(function(_editor)
4930
		{
4931
			self.mailvelope_editor = _editor;
4932
			editor.set_disabled(true);
4933
			mimeType.set_readonly(true);
4934
		},
4935
		function(_err)
4936
		{
4937
			self.egw.message(_err.message, 'error');
4938
		});
4939
	},
4940
4941
	/**
4942
	 * Switch sending PGP encrypted mail on and off
4943
	 *
4944
	 * @param {object} _action toolbar action
4945
	 */
4946
	togglePgpEncrypt: function (_action)
4947
	{
4948
		var self = this;
4949
		if (_action.checked)
4950
		{
4951
			if (typeof mailvelope == 'undefined')
4952
			{
4953
				this.mailvelopeInstallationOffer();
4954
				// switch encrypt button off again
4955
				this.et2.getWidgetById('composeToolbar')._actionManager.getActionById('pgp').set_checked(false);
4956
				jQuery('button#composeToolbar-pgp').toggleClass('toolbar_toggled');
4957
				return;
4958
			}
4959
			// check if we have keys for all recipents, before switching
4960
			this.mailvelopeGetCheckRecipients().then(function(_recipients)
4961
			{
4962
				var mimeType = self.et2.getWidgetById('mimeType');
4963
				// currently Mailvelope only supports plain-text, switch to it if necessary
4964
				if (mimeType.get_value())
4965
				{
4966
					mimeType.set_value(false);
4967
					self.et2._inst.submit();
4968
					return;	// ToDo: do that without reload
4969
				}
4970
				self.mailvelopeOpenKeyring().then(function(_keyring)
4971
				{
4972
					self.mailvelopeCompose(_keyring);
4973
				});
4974
			})
4975
			.catch(function(_err)
4976
			{
4977
				self.egw.message(_err.message, 'error');
4978
				self.et2.getWidgetById('composeToolbar')._actionManager.getActionById('pgp').set_checked(false);
4979
				jQuery('button#composeToolbar-pgp').toggleClass('toolbar_toggled');
4980
				return;
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
4981
			});
4982
		}
4983
		else
4984
		{
4985
			// switch Mailvelop off again, but warn user he will loose his content
4986
			et2_dialog.show_dialog(function (_button_id)
4987
			{
4988
				if (_button_id == et2_dialog.YES_BUTTON )
4989
				{
4990
					self.et2.getWidgetById('mimeType').set_readonly(false);
4991
					self.et2.getWidgetById('mail_plaintext').set_disabled(false);
4992
					jQuery(self.mailvelope_iframe_selector).remove();
4993
				}
4994
				else
4995
				{
4996
					self.et2.getWidgetById('composeToolbar').checkbox('pgp',true);
4997
				}
4998
			},
4999
			this.egw.lang('You will loose current message body, unless you save it to your clipboard!'),
5000
			this.egw.lang('Switch off encryption?'),
5001
			{}, et2_dialog.BUTTON_YES_NO, et2_dialog.WARNING_MESSAGE, undefined, this.egw);
5002
		}
5003
	},
5004
5005
	/**
5006
	 * Check if we have a key for all recipients
5007
	 *
5008
	 * @returns {Promise.<Array, Error>} Array of recipients or Error with recipients without key
5009
	 */
5010
	mailvelopeGetCheckRecipients: function()
5011
	{
5012
		// collect all recipients
5013
		var recipients = this.et2.getWidgetById('to').get_value();
5014
		recipients = recipients.concat(this.et2.getWidgetById('cc').get_value());
5015
		recipients = recipients.concat(this.et2.getWidgetById('bcc').get_value());
5016
5017
		return this._super.call(this, recipients);
5018
	},
5019
5020
	/**
5021
	 * Set the relevant widget to toolbar actions and submit
5022
	 *
5023
	 * @param {object|boolean} _action toolbar action or boolean value to stop extra call on
5024
	 * compose_integrated_submit
5025
	 */
5026
	compose_submitAction: function (_action)
5027
	{
5028
		if (this.compose_integrate_submit() && _action) return false;
5029
5030
		if (this.mailvelope_editor)
5031
		{
5032
			var self = this;
5033
			this.mailvelopeGetCheckRecipients().then(function(_recipients)
5034
			{
5035
				return self.mailvelope_editor.encrypt(_recipients);
5036
			}).then(function(_armored)
5037
			{
5038
				self.et2.getWidgetById('mimeType').set_value(false);
5039
				self.et2.getWidgetById('mail_plaintext').set_disabled(false);
5040
				self.et2.getWidgetById('mail_plaintext').set_value(_armored);
5041
				self.et2._inst.submit(null,null,true);
5042
			}).catch(function(_err)
5043
			{
5044
				self.egw.message(_err.message, 'error');
5045
			});
5046
			return false;
5047
		}
5048
		this.et2._inst.submit(null,null,true);
5049
	},
5050
5051
	/**
5052
	 * This function runs before client submit (send) mail to server
5053
	 * and takes care of mail integration modules to popup entry selection
5054
	 * dialog to give user a choice to which entry of selected app the compose
5055
	 * should be integereated.
5056
	 * @param {int|boolean} _integIndex
5057
	 *
5058
	 * @returns {Boolean} return true if to_tracker is checked otherwise false
5059
	 */
5060
	compose_integrate_submit: function (_integIndex)
5061
	{
5062
		if (_integIndex == false) return false;
5063
		var index = _integIndex || 0;
5064
		var integApps = ['to_tracker', 'to_infolog', 'to_calendar'];
5065
		var subject = this.et2.getWidgetById('subject');
5066
		var toolbar = this.et2.getWidgetById('composeToolbar');
5067
		var to_integrate_ids = this.et2.getWidgetById('to_integrate_ids');
5068
		var integWidget= {};
5069
		var self = this;
5070
5071
		integWidget = this.et2.getWidgetById(integApps[index]);
5072
		if (toolbar.options.actions[integApps[index]] &&
5073
				typeof toolbar.options.actions[integApps[index]]['mail_import'] != 'undefined' &&
5074
				typeof toolbar.options.actions[integApps[index]]['mail_import']['app_entry_method'] != 'unefined')
5075
		{
5076
			var mail_import_hook = toolbar.options.actions[integApps[index]]['mail_import']['app_entry_method'];
5077
			if (integWidget.get_value() == 'on')
5078
			{
5079
				this.integrate_checkAppEntry(egw.lang('Select %1 entry',integApps[index]), integApps[index].substr(3), subject.get_value(), '', mail_import_hook , function (args){
5080
					var value = {};
5081
					value[integApps[index]] = args.entryid;
5082
					var oldValue = to_integrate_ids.get_value()[0];
5083
					to_integrate_ids.set_value(jQuery.extend(value,oldValue));
5084
					index = index<integApps.length? ++index:false;
5085
					self.compose_integrate_submit(index);
5086
				});
5087
				return true;
5088
			}
5089
		}
5090
		else if(index<integApps.length)
5091
		{
5092
			this.compose_integrate_submit(++index);
5093
		}
5094
		else
5095
		{
5096
			this.compose_submitAction(false);
5097
		}
5098
		return false;
5099
	},
5100
5101
	/**
5102
	 * Set the selected checkbox action
5103
	 *
5104
	 * @param {type} _action selected toolbar action with checkbox
5105
	 * @returns {undefined}
5106
	 */
5107
	compose_setToggle: function (_action)
5108
	{
5109
		var widget = this.et2.getWidgetById (_action.id);
5110
		if (widget && typeof _action.checkbox != 'undefined' && _action.checkbox)
5111
		{
5112
			widget.set_value(_action.checked?"on":"off");
5113
		}
5114
	},
5115
5116
	/**
5117
	 * Set the selected priority value
5118
	 * @param {type} _action selected action
5119
	 * @returns {undefined}
5120
	 */
5121
	compose_priorityChange: function (_action)
5122
	{
5123
		var widget = this.et2.getWidgetById ('priority');
5124
		if (widget)
5125
		{
5126
			widget.set_value(_action.id);
5127
		}
5128
	},
5129
5130
	/**
5131
	 * Triger relative widget via its toolbar identical action
5132
	 * @param {type} _action toolbar action
5133
	 */
5134
	compose_triggerWidget:function (_action)
5135
	{
5136
		var widget = this.et2.getWidgetById(_action.id);
5137
		if (widget)
5138
		{
5139
			switch(widget.id)
5140
			{
5141
				case 'uploadForCompose':
5142
					document.getElementById('mail-compose_uploadForCompose').click();
5143
					break;
5144
				default:
5145
					widget.click();
5146
			}
5147
		}
5148
	},
5149
5150
	/**
5151
	 * Save drafted compose as eml file into VFS
5152
	 * @param {type} _action action
5153
	 */
5154
	compose_saveDraft2fm: function (_action)
5155
	{
5156
		var content = this.et2.getArrayMgr('content').data;
5157
		var subject = this.et2.getWidgetById('subject');
5158
		var elem = {0:{id:"", subject:""}};
5159
		if (typeof content != 'undefined' && content.lastDrafted && subject)
5160
		{
5161
			elem[0].id = content.lastDrafted;
5162
			elem[0].subject = subject.get_value();
5163
			this.mail_save2fm(_action, elem);
5164
		}
5165
		else
5166
		{
5167
			et2_dialog.alert('You need to save the message as draft first before to be able to save it into VFS','Save to filemanager','info');
5168
		}
5169
	},
5170
5171
	/**
5172
	 * Folder Management, opens the folder magnt. dialog
5173
	 * with the selected acc_id from index tree
5174
	 *
5175
	 * @param {egw action object} _action actions
5176
	 * @param {object} _senders selected node
5177
	 */
5178
	folderManagement: function (_action,_senders)
5179
	{
5180
		var acc_id = parseInt(_senders[0].id);
5181
		this.egw.open_link('mail.mail_ui.folderManagement&acc_id='+acc_id, '_blank', '720x500');
5182
	},
5183
5184
	/**
5185
	 * Show ajax-loader when the autoloading get started
5186
	 *
5187
	 * @param {type} _id item id
5188
	 * @param {type} _widget tree widget
5189
	 * @returns {Boolean}
5190
	 */
5191
	folderMgmt_autoloadingStart: function(_id, _widget)
5192
	{
5193
		return this.subscription_autoloadingStart (_id, _widget);
5194
	},
5195
5196
	/**
5197
	 * Revert back the icon after autoloading is finished
5198
	 * @param {type} _id item id
5199
	 * @param {type} _widget tree widget
5200
	 * @returns {Boolean}
5201
	 */
5202
	folderMgmt_autoloadingEnd: function(_id, _widget)
5203
	{
5204
		return true;
5205
	},
5206
5207
	/**
5208
	 *
5209
	 * @param {type} _ids
5210
	 * @param {type} _widget
5211
	 * @returns {undefined}
5212
	 */
5213
	folderMgmt_onSelect: function(_ids, _widget)
5214
	{
5215
		// Flag to reset selected items
5216
		var resetSelection = false;
5217
5218
		var self = this;
5219
5220
		/**
5221
		 * helper function to multiselect range of nodes in same level
5222
		 *
5223
		 * @param {string} _a start node id
5224
		 * @param {string} _b end node id
5225
		 * @param {string} _branch totall node ids in the level
5226
		 */
5227
		var rangeSelector = function(_a,_b, _branch)
5228
		{
5229
			var branchItems = _branch.split(_widget.input.dlmtr);
5230
			var _aIndex = _widget.input.getIndexById(_a);
5231
			var _bIndex = _widget.input.getIndexById(_b);
5232
			if (_bIndex<_aIndex)
5233
			{
5234
				var tmpIndex = _aIndex;
5235
				_aIndex = _bIndex;
5236
				_bIndex = tmpIndex;
5237
			}
5238
			for(var i =_aIndex;i<=_bIndex;i++)
5239
			{
5240
				self.folderMgmt_setCheckbox(_widget, branchItems[i], !_widget.input.isItemChecked(branchItems[i]));
5241
			}
5242
		};
5243
5244
		// extract items ids
5245
		var itemIds = _ids.split(_widget.input.dlmtr);
5246
5247
		if(itemIds.length == 2) // there's a range selected
5248
		{
5249
			var branch = _widget.input.getSubItems(_widget.input.getParentId(itemIds[0]));
5250
			// Set range of selected/unselected
5251
			rangeSelector(itemIds[0], itemIds[1], branch);
5252
		}
5253
		else if(itemIds.length != 1)
5254
		{
5255
			resetSelection = true;
5256
		}
5257
5258
		if (resetSelection)
5259
		{
5260
			_widget.input._unselectItems();
5261
		}
5262
	},
5263
5264
	/**
5265
	 * Set enable/disable checkbox
5266
	 *
5267
	 * @param {object} _widget tree widget
5268
	 * @param {string} _itemId item tree id
5269
	 * @param {boolean} _stat - status to be set on checkbox true/false
5270
	 */
5271
	folderMgmt_setCheckbox: function (_widget, _itemId, _stat)
5272
	{
5273
		if (_widget)
5274
		{
5275
			_widget.input.setCheck(_itemId, _stat);
5276
			_widget.input.setSubChecked(_itemId,_stat);
5277
		}
5278
	},
5279
5280
	/**
5281
	 *
5282
	 * @param {type} _id
5283
	 * @param {type} _widget
5284
	 * @TODO: Implement onCheck handler in order to select or deselect subItems
5285
	 *	of a checked parent node
5286
	 */
5287
	folderMgmt_onCheck: function (_id, _widget)
5288
	{
5289
		var selected = _widget.input.getAllChecked();
5290
		if (selected && selected.split(_widget.input.dlmtr).length > 5)
5291
		{
5292
			egw.message(egw.lang('If you would like to select multiple folders in one action, you can hold ctrl key then select a folder as start range and another folder within a same level as end range, all folders in between will be selected or unselected based on their current status.'));
5293
		}
5294
	},
5295
5296
	/**
5297
	 * Detele button handler
5298
	 * triggers longTask dialog and send delete operation url
5299
	 *
5300
	 */
5301
	folderMgmt_deleteBtn: function ()
5302
	{
5303
		var tree = etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('tree');
5304
		var menuaction= 'mail.mail_ui.ajax_folderMgmt_delete';
5305
5306
		var callbackDialog = function(_btn)
5307
		{
5308
			egw.appName='mail';
5309
			if (_btn === et2_dialog.YES_BUTTON)
5310
			{
5311
				if (tree)
5312
				{
5313
					var selFolders = tree.input.getAllChecked();
5314
					if (selFolders)
5315
					{
5316
						var selFldArr = selFolders.split(tree.input.dlmtr);
5317
						var msg = egw.lang('Deleting %1 folders in progress ...', selFldArr.length);
5318
						et2_dialog.long_task(function(_val, _resp){
5319
							console.log(_val, _resp);
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
5320
							if (_val && _resp.type !== 'error')
5321
							{
5322
								var stat = [];
5323
								var folderName = '';
5324
								for(var i=0;i<selFldArr.length;i++)
5325
								{
5326
									folderName = selFldArr[i].split('::');
5327
									stat[selFldArr[i]] = folderName[1];
5328
								}
5329
								// delete the item from index folderTree
5330
								egw.window.app.mail.mail_removeLeaf(stat);
5331
							}
5332
							else
5333
							{
5334
								// submit
5335
								etemplate2.getByApplication('mail')[0].widgetContainer._inst.submit();
5336
							}
5337
						}, msg, egw.lang('Deleting folders'), menuaction, selFldArr, 'mail');
5338
						return true;
5339
					}
5340
				}
5341
			}
5342
		};
5343
		et2_dialog.show_dialog(callbackDialog, this.egw.lang('Are you sure you want to delete all selected folders?'), this.egw.lang('Delete folder'), {},
5344
			et2_dialog.BUTTON_YES_NO, et2_dialog.WARNING_MESSAGE, undefined, egw);
5345
	},
5346
5347
	/**
5348
	 * Implement mobile view
5349
	 *
5350
	 * @param {type} _action
5351
	 * @param {type} _sender
5352
	 */
5353
	mobileView: function(_action, _sender)
5354
	{
5355
		// row id in nm
5356
		var id = _sender[0].id;
5357
5358
		var defaultActions= {
5359
			actions:['delete', 'forward','reply','flagged'], // default actions to display
5360
			check:function(_action){
5361
				for (var i=0;i<= this.actions.length;i++)
5362
				{
5363
					if (_action == this.actions[i]) return true;
5364
				}
5365
				return false;
5366
			}
5367
		};
5368
5369
		var content = {};
5370
		var self = this;
5371
5372
		if (id){
5373
			content = egw.dataGetUIDdata(id);
5374
			content.data['toolbar'] = this.et2.getArrayMgr('sel_options').getEntry('toolbar');
5375
			// Set default actions
5376
			for(var action in content.data['toolbar'])
5377
			{
5378
				content.data.toolbar[action]['toolbarDefault'] = defaultActions.check(action);
5379
			}
5380
			// update local storage with added toolbar actions
5381
			egw.dataStoreUID(id,content.data);
5382
		}
5383
5384
		this.viewEntry(_action, _sender, true, function(etemplate){
5385
			// et2 object in view
5386
			var et2 = etemplate.widgetContainer;
5387
			// iframe to load message
5388
			var iframe = et2.getWidgetById('iframe');
5389
			// toolbar widget
5390
			var toolbar = et2.getWidgetById('toolbar');
5391
			// attachments details title DOM node
5392
			var $attachment = jQuery('.attachments span.et2_details_title');
5393
			// details DOM
5394
			var $details = jQuery('.et2_details.details');
5395
			// Content
5396
			var content = et2.getArrayMgr('content').data;
5397
5398
			// set the current selected row
5399
			et2.mail_currentlyFocussed = id;
5400
5401
			if (content.attachmentsBlock.length>0 && content.attachmentsBlock[0].filename)
5402
			{
5403
				$attachment.text(self.egw.lang('%1 attachments', content.attachmentsBlock.length));
5404
			}
5405
			else
5406
			{
5407
				// disable attachments area if there's no attachments
5408
				$attachment.parent().hide();
5409
			}
5410
			// disable the detials if there's no details
5411
			if (!content.ccaddress && !content.additionaltoaddress) $details.hide();
5412
5413
			toolbar.set_actions(content.toolbar);
5414
			var toaddressdetails = self.et2_view.widgetContainer.getWidgetById('toaddressdetails');
5415
			if (toaddressdetails && content.additionaltoaddress)
5416
			{
5417
				toaddressdetails.set_value('... ' +content.additionaltoaddress.length + egw.lang(' more'));
5418
				jQuery(toaddressdetails.getDOMNode()).off().on('click', function(){
5419
					$details.find('.et2_details_toggle').click();
5420
				});
5421
			}
5422
5423
			// Request email body from server
5424
			iframe.set_src(egw.link('/index.php',{menuaction:'mail.mail_ui.loadEmailBody',_messageID:id}));
5425
			jQuery(iframe.getDOMNode()).on('load',function(){
5426
5427
				if (jQuery(this.contentWindow.document.body).find('#calendar-meeting').length > 0)
5428
				{
5429
					var frame = this;
5430
					jQuery(this).show();
5431
					// calendar meeting mails still need to be in iframe, therefore, we calculate the height
5432
					// and set the iframe with a fixed height to be able to see all content without getting
5433
					// scrollbar becuase of scrolling issue in iframe
5434
					window.setTimeout(function(){jQuery(frame).height(frame.contentWindow.document.body.scrollHeight);}, 500);
5435
				}
5436
				else
5437
				{
5438
					// Use prepare print function to copy iframe content into div
5439
					// as we don't want to show content in iframe (scrolling problem).
5440
					self.mail_prepare_print(jQuery(this));
5441
				}
5442
5443
5444
			});
5445
		});
5446
	}
5447
});
5448